diff --git a/core/src/main/cpp/main/include/art/runtime/jit/jit_code_cache.h b/core/src/main/cpp/main/include/art/runtime/jit/jit_code_cache.h
new file mode 100644
index 00000000..73f2ec10
--- /dev/null
+++ b/core/src/main/cpp/main/include/art/runtime/jit/jit_code_cache.h
@@ -0,0 +1,52 @@
+/*
+ * This file is part of LSPosed.
+ *
+ * LSPosed is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LSPosed is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with LSPosed. If not, see .
+ *
+ * Copyright (C) 2021 LSPosed Contributors
+ */
+
+#pragma once
+
+#include
+#include
+#include "jni/yahfa.h"
+
+namespace art {
+ namespace jit {
+ namespace jit_code_cache {
+ CREATE_MEM_FUNC_SYMBOL_ENTRY(void, MoveObsoleteMethod, void *thiz,
+ void *old_method, void *new_method) {
+ if (MoveObsoleteMethodSym)
+ [[likely]] MoveObsoleteMethodSym(thiz, old_method, new_method);
+ }
+
+ CREATE_MEM_HOOK_STUB_ENTRIES(
+ "_ZN3art3jit12JitCodeCache19GarbageCollectCacheEPNS_6ThreadE",
+ void, GarbageCollectCache, (void * thiz, void * self), {
+ LOGD("Before jit cache gc, moving hooked methods");
+ for (auto[target, backup] : lspd::getJitMovements()) {
+ MoveObsoleteMethod(thiz, target, backup);
+ }
+ backup(thiz, self);
+ });
+
+ inline void Setup(const SandHook::ElfImg &handle) {
+ RETRIEVE_MEM_FUNC_SYMBOL(MoveObsoleteMethod,
+ "_ZN3art3jit12JitCodeCache18MoveObsoleteMethodEPNS_9ArtMethodES3_");
+ lspd::HookSyms(handle, GarbageCollectCache);
+ }
+ }
+ }
+}
diff --git a/core/src/main/cpp/main/include/art/runtime/jit/profiling_info.h b/core/src/main/cpp/main/include/art/runtime/jit/profiling_info.h
deleted file mode 100644
index 5c0c2a25..00000000
--- a/core/src/main/cpp/main/include/art/runtime/jit/profiling_info.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * This file is part of LSPosed.
- *
- * LSPosed is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * LSPosed is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with LSPosed. If not, see .
- *
- * Copyright (C) 2021 LSPosed Contributors
- */
-
-#pragma once
-
-#include
-#include
-#include
-#include "utils.h"
-#include "jni/pending_hooks.h"
-
-namespace art {
- namespace profiling_info {
- inline static size_t OFFSET_art_method = -1;
-
- CREATE_MEM_HOOK_STUB_ENTRIES(
- "_ZN3art13ProfilingInfo13AddInvokeInfoEjPNS_6mirror5ClassE",
- void, AddInvokeInfo, (void * thiz, uint32_t dex_pc, void * clazz_ptr), {
- void *method = *reinterpret_cast(
- reinterpret_cast(thiz) + OFFSET_art_method);
- if (lspd::isHooked(method)) [[unlikely]] return;
- backup(thiz, dex_pc, clazz_ptr);
- });
-
- static void Setup(const SandHook::ElfImg &handle) {
- int api_level = lspd::GetAndroidApiLevel();
- switch (api_level) {
- case __ANDROID_API_Q__:
- OFFSET_art_method = 0;
- break;
- case __ANDROID_API_O_MR1__:
- [[fallthrough]];
- case __ANDROID_API_P__:
- [[fallthrough]];
- case __ANDROID_API_R__:
- [[fallthrough]];
- case __ANDROID_API_S__:
- if constexpr(lspd::is64) {
- OFFSET_art_method = 8;
- } else {
- OFFSET_art_method = 4;
- }
- break;
- }
- if (OFFSET_art_method != size_t(-1))
- lspd::HookSyms(handle, AddInvokeInfo);
- }
- }
-}
diff --git a/core/src/main/cpp/main/src/jni/yahfa.cpp b/core/src/main/cpp/main/src/jni/yahfa.cpp
index 49179ee7..213bd092 100644
--- a/core/src/main/cpp/main/src/jni/yahfa.cpp
+++ b/core/src/main/cpp/main/src/jni/yahfa.cpp
@@ -35,6 +35,9 @@ namespace lspd {
namespace {
std::unordered_set hooked_methods_;
std::shared_mutex hooked_methods_lock_;
+
+ std::vector> jit_movements_;
+ std::shared_mutex jit_movements_lock_;
}
bool isHooked(void *art_method) {
@@ -47,7 +50,18 @@ namespace lspd {
hooked_methods_.insert(art_method);
}
+ void recordJitMovement(void *target, void* backup) {
+ std::unique_lock lk(jit_movements_lock_);
+ jit_movements_.emplace_back(target, backup);
+ }
+
+ std::vector> getJitMovements() {
+ std::unique_lock lk(jit_movements_lock_);
+ return std::move(jit_movements_);
+ }
+
using namespace startop::dex;
+
LSP_DEF_NATIVE_METHOD(void, Yahfa, init, jint sdkVersion) {
yahfa::init(env, clazz, sdkVersion);
}
@@ -59,16 +73,20 @@ namespace lspd {
}
LSP_DEF_NATIVE_METHOD(jboolean, Yahfa, backupAndHookNative, jobject target,
- jobject hook, jobject backup) {
+ jobject hook, jobject backup, jboolean is_proxy) {
art::gc::ScopedGCCriticalSection section(art::Thread::Current().Get(),
art::gc::kGcCauseDebugger,
art::gc::kCollectorTypeDebugger);
art::thread_list::ScopedSuspendAll suspend("Yahfa Hook", false);
- return yahfa::backupAndHookNative(env, clazz, target, hook, backup);
- }
-
- LSP_DEF_NATIVE_METHOD(void, Yahfa, recordHooked, jobject member) {
- lspd::recordHooked(yahfa::getArtMethod(env, member));
+ if (yahfa::backupAndHookNative(env, clazz, target, hook, backup)) {
+ auto *target_method = yahfa::getArtMethod(env, target);
+ auto *backup_method = yahfa::getArtMethod(env, backup);
+ recordHooked(target_method);
+ if (!is_proxy) [[likely]] recordJitMovement(target_method, backup_method);
+ return JNI_TRUE;
+ } else {
+ return JNI_FALSE;
+ }
}
LSP_DEF_NATIVE_METHOD(jboolean, Yahfa, isHooked, jobject member) {
@@ -80,7 +98,7 @@ namespace lspd {
static auto *kInMemoryClassloader = JNI_NewGlobalRef(env, JNI_FindClass(env,
"dalvik/system/InMemoryDexClassLoader"));
static jmethodID kInitMid = JNI_GetMethodID(env, kInMemoryClassloader, "",
- "(Ljava/nio/ByteBuffer;Ljava/lang/ClassLoader;)V");
+ "(Ljava/nio/ByteBuffer;Ljava/lang/ClassLoader;)V");
DexBuilder dex_file;
auto parameter_length = env->GetArrayLength(classes);
@@ -116,10 +134,10 @@ namespace lspd {
hook_builder.BuildNewArray(hook_params_array, TypeDescriptor::Object, tmp);
for (size_t i = 0U, j = 0U; i < parameter_types.size(); ++i, ++j) {
hook_builder.BuildBoxIfPrimitive(Value::Parameter(j), parameter_types[i],
- Value::Parameter(j));
+ Value::Parameter(j));
hook_builder.BuildConst(tmp, i);
hook_builder.BuildAput(Instruction::Op::kAputObject, hook_params_array,
- Value::Parameter(j), tmp);
+ Value::Parameter(j), tmp);
if (parameter_types[i].is_wide()) ++j;
}
auto handle_hook_method{dex_file.GetOrDeclareMethod(
@@ -171,10 +189,10 @@ namespace lspd {
env->DeleteLocalRef(dex_buffer);
static jmethodID kMid = JNI_GetMethodID(env, kInMemoryClassloader, "loadClass",
- "(Ljava/lang/String;)Ljava/lang/Class;");
+ "(Ljava/lang/String;)Ljava/lang/Class;");
if (!kMid) {
kMid = JNI_GetMethodID(env, kInMemoryClassloader, "findClass",
- "(Ljava/lang/String;)Ljava/lang/Class;");
+ "(Ljava/lang/String;)Ljava/lang/Class;");
}
auto target = JNI_CallObjectMethod(env, my_cl, kMid, env->NewStringUTF("LspHooker_"));
// LOGD("Created %zd", image.size());
@@ -189,8 +207,7 @@ namespace lspd {
LSP_NATIVE_METHOD(Yahfa, findMethodNative,
"(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/reflect/Executable;"),
LSP_NATIVE_METHOD(Yahfa, backupAndHookNative,
- "(Ljava/lang/reflect/Executable;Ljava/lang/reflect/Method;Ljava/lang/reflect/Method;)Z"),
- LSP_NATIVE_METHOD(Yahfa, recordHooked, "(Ljava/lang/reflect/Executable;)V"),
+ "(Ljava/lang/reflect/Executable;Ljava/lang/reflect/Method;Ljava/lang/reflect/Method;Z)Z"),
LSP_NATIVE_METHOD(Yahfa, isHooked, "(Ljava/lang/reflect/Executable;)Z"),
LSP_NATIVE_METHOD(Yahfa, buildHooker,
"(Ljava/lang/ClassLoader;C[CLjava/lang/String;)Ljava/lang/Class;"),
diff --git a/core/src/main/cpp/main/src/jni/yahfa.h b/core/src/main/cpp/main/src/jni/yahfa.h
index b3c04203..fe16429f 100644
--- a/core/src/main/cpp/main/src/jni/yahfa.h
+++ b/core/src/main/cpp/main/src/jni/yahfa.h
@@ -21,12 +21,14 @@
#pragma once
#include "jni.h"
+#include
+#include
namespace lspd {
bool isHooked(void* art_method);
- void recordHooked(void* art_method);
+ std::vector> getJitMovements();
void RegisterYahfa(JNIEnv *);
diff --git a/core/src/main/cpp/main/src/native_hook.cpp b/core/src/main/cpp/main/src/native_hook.cpp
index f6cf1a13..7760fbcf 100644
--- a/core/src/main/cpp/main/src/native_hook.cpp
+++ b/core/src/main/cpp/main/src/native_hook.cpp
@@ -36,7 +36,7 @@
#include "art/runtime/instrumentation.h"
#include "art/runtime/thread_list.h"
#include "art/runtime/gc/scoped_gc_critical_section.h"
-#include "art/runtime/jit/profiling_info.h"
+#include "art/runtime/jit/jit_code_cache.h"
namespace lspd {
static std::atomic_bool installed = false;
@@ -61,7 +61,7 @@ namespace lspd {
art::instrumentation::DisableUpdateHookedMethodsCode(handle_libart);
art::thread_list::ScopedSuspendAll::Setup(handle_libart);
art::gc::ScopedGCCriticalSection::Setup(handle_libart);
- art::profiling_info::Setup(handle_libart);
+ art::jit::jit_code_cache::Setup(handle_libart);
art_img.reset();
LOGD("Inline hooks installed");
}
diff --git a/core/src/main/java/org/lsposed/lspd/core/yahfa/HookMain.java b/core/src/main/java/org/lsposed/lspd/core/yahfa/HookMain.java
index c89b189e..b31694e9 100644
--- a/core/src/main/java/org/lsposed/lspd/core/yahfa/HookMain.java
+++ b/core/src/main/java/org/lsposed/lspd/core/yahfa/HookMain.java
@@ -27,6 +27,7 @@ import java.lang.reflect.Constructor;
import java.lang.reflect.Executable;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
+import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Arrays;
@@ -51,10 +52,8 @@ public class HookMain {
// backup is just a placeholder and the constraint could be less strict
checkCompatibleMethods(target, backup, "Backup");
}
- if(!Yahfa.backupAndHookNative(target, hook, backup)){
+ if (!Yahfa.backupAndHookNative(target, hook, backup, Proxy.isProxyClass(target.getDeclaringClass()))) {
throw new RuntimeException("Failed to hook " + target + " with " + hook);
- } else {
- Yahfa.recordHooked(target);
}
}
diff --git a/core/src/main/java/org/lsposed/lspd/nativebridge/Yahfa.java b/core/src/main/java/org/lsposed/lspd/nativebridge/Yahfa.java
index 4105f2f4..7dd091da 100644
--- a/core/src/main/java/org/lsposed/lspd/nativebridge/Yahfa.java
+++ b/core/src/main/java/org/lsposed/lspd/nativebridge/Yahfa.java
@@ -25,15 +25,13 @@ import java.lang.reflect.Method;
public class Yahfa {
- public static native boolean backupAndHookNative(Executable target, Method hook, Method backup);
+ public static native boolean backupAndHookNative(Executable target, Method hook, Method backup, boolean isProxy);
// JNI.ToReflectedMethod() could return either Method or Constructor
public static native Executable findMethodNative(Class> targetClass, String methodName, String methodSig);
public static native void init(int sdkVersion);
- public static native void recordHooked(Executable member);
-
public static native boolean isHooked(Executable member);
public static native Class> buildHooker(ClassLoader appClassLoader, char returnType, char[] params, String methodName);
diff --git a/core/src/main/java/org/lsposed/lspd/service/ConfigFileManager.java b/core/src/main/java/org/lsposed/lspd/service/ConfigFileManager.java
index 72cbd23d..2ef9d316 100644
--- a/core/src/main/java/org/lsposed/lspd/service/ConfigFileManager.java
+++ b/core/src/main/java/org/lsposed/lspd/service/ConfigFileManager.java
@@ -58,8 +58,6 @@ public class ConfigFileManager {
DateTimeFormatter.ISO_LOCAL_DATE_TIME.withZone(Utils.getZoneId());
@SuppressWarnings("FieldCanBeLocal")
private static FileLocker locker = null;
- @SuppressWarnings("FieldCanBeLocal")
- private static AssetManager am = null;
private static Resources res = null;
private static ParcelFileDescriptor fd = null;
@@ -119,7 +117,7 @@ public class ConfigFileManager {
private static void loadRes() {
if (res != null) return;
try {
- am = AssetManager.class.newInstance();
+ var am = AssetManager.class.newInstance();
//noinspection JavaReflectionMemberAccess DiscouragedPrivateApi
Method addAssetPath = AssetManager.class.getDeclaredMethod("addAssetPath", String.class);
addAssetPath.setAccessible(true);