Skip to content

Commit 1212e45

Browse files
MlgmXyysdLoveSy
and
LoveSy
committed
Fix PendingHook
This will fix the random failure of static method hook Co-Authored-By: LoveSy <[email protected]>
1 parent 235ee81 commit 1212e45

File tree

8 files changed

+78
-90
lines changed

8 files changed

+78
-90
lines changed

Diff for: edxp-common/src/main/java/com/elderdrivers/riru/edxp/util/ClassUtils.java

+6-6
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
import android.os.Build;
44

5-
import java.lang.reflect.Constructor;
65
import java.lang.reflect.Member;
6+
import java.lang.reflect.Method;
77
import java.lang.reflect.Modifier;
88

99
import de.robv.android.xposed.XposedHelpers;
@@ -29,14 +29,14 @@ public static int getClassStatus(Class clazz, boolean isUnsigned) {
2929
* 5.0-8.0: kInitialized = 10 int
3030
* 8.1: kInitialized = 11 int
3131
* 9.0+: kInitialized = 14 uint8_t
32-
* 11.0+: kVisiblyInitialized = 15 uint8_t
32+
* 11.0+: kInitialized = 14 uint8_t
33+
* kVisiblyInitialized = 15 uint8_t
3334
*/
3435
@ApiSensitive(Level.MIDDLE)
3536
public static boolean isInitialized(Class clazz) {
3637
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
37-
return getClassStatus(clazz, true) == 15;
38-
}
39-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
38+
return getClassStatus(clazz, true) >= 14;
39+
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
4040
return getClassStatus(clazz, true) == 14;
4141
} else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.O_MR1) {
4242
return getClassStatus(clazz, false) == 11;
@@ -46,7 +46,7 @@ public static boolean isInitialized(Class clazz) {
4646
}
4747

4848
public static boolean shouldDelayHook(Member hookMethod) {
49-
if (hookMethod == null || hookMethod instanceof Constructor) {
49+
if (!(hookMethod instanceof Method)) {
5050
return false;
5151
}
5252
Class declaringClass = hookMethod.getDeclaringClass();

Diff for: edxp-core/src/main/cpp/main/include/art/runtime/art_method.h

-62
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,6 @@
1010

1111
namespace art {
1212
namespace art_method {
13-
14-
inline static size_t oat_header_length;
15-
inline static int32_t oat_header_code_length_offset;
16-
1713
CREATE_MEM_FUNC_SYMBOL_ENTRY(std::string, PrettyMethod, void *thiz, bool with_signature) {
1814
if (UNLIKELY(thiz == nullptr))
1915
return "null";
@@ -26,66 +22,8 @@ namespace art {
2622
return PrettyMethod(thiz, true);
2723
}
2824

29-
CREATE_MEM_HOOK_STUB_ENTRIES(
30-
LP_SELECT("_ZN3art9ArtMethod23GetOatQuickMethodHeaderEj", "_ZN3art9ArtMethod23GetOatQuickMethodHeaderEm"),
31-
void *, GetOatQuickMethodHeader,
32-
(void * thiz, uintptr_t pc), {
33-
// This is a partial copy from AOSP. We only touch them if they are hooked.
34-
if (UNLIKELY(edxp::isHooked(thiz))) {
35-
uintptr_t original_ep =
36-
reinterpret_cast<uintptr_t>(getOriginalEntryPointFromTargetMethod(
37-
thiz)) & ~0x1;
38-
if (original_ep) {
39-
char *code_length_loc =
40-
reinterpret_cast<char *>(original_ep) +
41-
oat_header_code_length_offset;
42-
uint32_t code_length =
43-
*reinterpret_cast<uint32_t *>(code_length_loc) &
44-
~0x80000000u;
45-
LOGD("art_method::GetOatQuickMethodHeader: ArtMethod=%p (%s), isHooked=true, original_ep=0x%zux, code_length=0x%x, pc=0x%zux",
46-
thiz, PrettyMethod(thiz).c_str(),
47-
original_ep, code_length, pc);
48-
if (original_ep <= pc &&
49-
pc <= original_ep + code_length)
50-
return reinterpret_cast<void *>(
51-
original_ep -
52-
oat_header_length);
53-
// If PC is not in range, we mark it as not found.
54-
LOGD("art_method::GetOatQuickMethodHeader: PC not found in current method.");
55-
return nullptr;
56-
} else {
57-
LOGD("art_method::GetOatQuickMethodHeader: ArtMethod=%p (%s) isHooked but not backup, fallback to system",
58-
thiz, PrettyMethod(thiz).c_str());
59-
}
60-
}
61-
return backup(thiz, pc);
62-
});
63-
6425
static void Setup(void *handle, HookFunType hook_func) {
6526
LOGD("art_method hook setup, handle=%p", handle);
66-
int api_level = edxp::GetAndroidApiLevel();
67-
switch (api_level) {
68-
case __ANDROID_API_O__:
69-
[[fallthrough]];
70-
case __ANDROID_API_O_MR1__:
71-
[[fallthrough]];
72-
case __ANDROID_API_P__:
73-
oat_header_length = 24;
74-
oat_header_code_length_offset = -4;
75-
break;
76-
default:
77-
LOGW("No valid offset in SDK %d for oat_header_length, using offset from Android R",
78-
api_level);
79-
[[fallthrough]];
80-
case __ANDROID_API_Q__:
81-
[[fallthrough]];
82-
case __ANDROID_API_R__:
83-
oat_header_length = 8;
84-
oat_header_code_length_offset = -4;
85-
break;
86-
}
87-
edxp::HookSyms(handle, hook_func, GetOatQuickMethodHeader);
88-
8927
RETRIEVE_MEM_FUNC_SYMBOL(PrettyMethod, "_ZN3art9ArtMethod12PrettyMethodEb");
9028
}
9129
}

Diff for: edxp-core/src/main/cpp/main/include/art/runtime/class_linker.h

+19-8
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ namespace art {
3434
LOGD("Pending hook for %p (%s)", clazz_ptr,
3535
art::mirror::Class(clazz_ptr).GetDescriptor().c_str());
3636
edxp::Context::GetInstance()->CallOnPostFixupStaticTrampolines(clazz_ptr);
37+
edxp::DonePendingHook(class_def);
3738
}
3839
}
3940

@@ -45,11 +46,12 @@ namespace art {
4546
});
4647

4748
CREATE_MEM_HOOK_STUB_ENTRIES(
48-
"_ZN3art11ClassLinker22FixupStaticTrampolinesEPNS_6ThreadENS_6ObjPtrINS_6mirror5ClassEEE",
49-
void, FixupStaticTrampolinesWithThread, (void * thiz,
50-
void * thread, void * clazz_ptr), {
51-
backup(thiz, thread, clazz_ptr);
52-
MaybeDelayHook(clazz_ptr);
49+
"_ZN3art11ClassLinker20MarkClassInitializedEPNS_6ThreadENS_6HandleINS_6mirror5ClassEEE",
50+
void*, MarkClassInitialized, (void * thiz, void * self, uint32_t * clazz_ptr), {
51+
void *result = backup(thiz, self, clazz_ptr);
52+
auto ptr = reinterpret_cast<void *>(*clazz_ptr);
53+
MaybeDelayHook(ptr);
54+
return result;
5355
});
5456

5557
CREATE_MEM_FUNC_SYMBOL_ENTRY(void, MakeInitializedClassesVisiblyInitialized, void *thiz,
@@ -63,7 +65,7 @@ namespace art {
6365
"_ZN3art11ClassLinker30ShouldUseInterpreterEntrypointEPNS_9ArtMethodEPKv",
6466
bool, ShouldUseInterpreterEntrypoint, (void * art_method,
6567
const void *quick_code), {
66-
if (quick_code != nullptr && UNLIKELY(edxp::isHooked(art_method))) {
68+
if (quick_code != nullptr && UNLIKELY(edxp::isHooked(art_method) || edxp::IsMethodPending(art_method))) {
6769
return false;
6870
}
6971
return backup(art_method, quick_code);
@@ -126,10 +128,19 @@ namespace art {
126128
RETRIEVE_MEM_FUNC_SYMBOL(SetEntryPointsToInterpreter,
127129
"_ZNK3art11ClassLinker27SetEntryPointsToInterpreterEPNS_9ArtMethodE");
128130

129-
edxp::HookSyms(handle, hook_func, FixupStaticTrampolines,
130-
FixupStaticTrampolinesWithThread);
131131
edxp::HookSyms(handle, hook_func, ShouldUseInterpreterEntrypoint);
132132

133+
if (api_level >= __ANDROID_API_R__) {
134+
// In android R, FixupStaticTrampolines won't be called unless it's marking it as
135+
// visiblyInitialized.
136+
// So we miss some calls between initialized and visiblyInitialized.
137+
// Therefore we hook the new introduced MarkClassInitialized instead
138+
// This only happens on non-x86 devices
139+
edxp::HookSyms(handle, hook_func, MarkClassInitialized);
140+
} else {
141+
edxp::HookSyms(handle, hook_func, FixupStaticTrampolines);
142+
}
143+
133144
// MakeInitializedClassesVisiblyInitialized will cause deadlock
134145
// IsQuickToInterpreterBridge is inlined
135146
// So we use GetSavedEntryPointOfPreCompiledMethod instead

Diff for: edxp-core/src/main/cpp/main/src/edxp_context.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ namespace edxp {
218218
if (!ConfigManager::GetInstance()->IsInitialized()) {
219219
LOGE("skip injecting into android because configurations are not loaded properly");
220220
}
221-
if (skip_ && !ConfigManager::GetInstance()->IsAppNeedHook("android")) {
221+
if (!skip_ && !ConfigManager::GetInstance()->IsAppNeedHook("android")) {
222222
skip_ = true;
223223
LOGD("skip injecting into android because it's whitelisted/blacklisted");
224224
}

Diff for: edxp-core/src/main/cpp/main/src/jni/edxp_pending_hooks.cpp

+42-9
Original file line numberDiff line numberDiff line change
@@ -11,33 +11,66 @@
1111
#include "art/runtime/mirror/class.h"
1212

1313
namespace edxp {
14+
namespace {
15+
std::unordered_set<const void *> pending_classes_;
16+
std::shared_mutex pending_classes_lock_;
1417

15-
static std::unordered_set<const void *> pending_classes_;
16-
static std::shared_mutex pending_classes_lock_;
18+
std::unordered_set<const void *> pending_methods_;
19+
std::shared_mutex pending_methods_lock_;
1720

18-
static std::unordered_set<const void *> hooked_methods_;
19-
static std::shared_mutex hooked_methods_lock_;
21+
std::unordered_set<const void *> hooked_methods_;
22+
std::shared_mutex hooked_methods_lock_;
23+
}
2024

2125
bool IsClassPending(void *clazz) {
2226
std::shared_lock lk(pending_classes_lock_);
2327
return pending_classes_.count(clazz);
2428
}
2529

26-
static void PendingHooks_recordPendingMethodNative(JNI_START, jclass class_ref) {
30+
bool IsMethodPending(void *art_method) {
31+
bool result;
32+
{
33+
std::shared_lock lk(pending_methods_lock_);
34+
result = pending_methods_.count(art_method);
35+
}
36+
if (result) {
37+
std::unique_lock lk(pending_methods_lock_);
38+
pending_methods_.erase(art_method);
39+
}
40+
return result;
41+
}
42+
43+
void DonePendingHook(void *clazz) {
44+
std::unique_lock lk(pending_classes_lock_);
45+
pending_classes_.erase(clazz);
46+
}
47+
48+
static void
49+
PendingHooks_recordPendingMethodNative(JNI_START, jobject method_ref, jclass class_ref) {
2750
auto *class_ptr = art::Thread::Current().DecodeJObject(class_ref);
51+
auto *method = getArtMethod(env, method_ref);
2852
art::mirror::Class mirror_class(class_ptr);
2953
if (auto def = mirror_class.GetClassDef(); LIKELY(def)) {
30-
LOGD("record pending: %p (%s)", class_ptr, mirror_class.GetDescriptor().c_str());
31-
std::unique_lock lk(pending_classes_lock_);
32-
pending_classes_.insert(def);
54+
LOGD("record pending: %p (%s) with %p", class_ptr, mirror_class.GetDescriptor().c_str(),
55+
method);
56+
// Add it for ShouldUseInterpreterEntrypoint
57+
{
58+
std::unique_lock lk(pending_methods_lock_);
59+
pending_methods_.insert(method);
60+
}
61+
{
62+
std::unique_lock lk(pending_classes_lock_);
63+
pending_classes_.insert(def);
64+
}
3365
} else {
3466
LOGW("fail to record pending for : %p (%s)", class_ptr,
3567
mirror_class.GetDescriptor().c_str());
3668
}
3769
}
3870

3971
static JNINativeMethod gMethods[] = {
40-
NATIVE_METHOD(PendingHooks, recordPendingMethodNative, "(Ljava/lang/Class;)V"),
72+
NATIVE_METHOD(PendingHooks, recordPendingMethodNative,
73+
"(Ljava/lang/reflect/Method;Ljava/lang/Class;)V"),
4174
};
4275

4376
void RegisterPendingHooks(JNIEnv *env) {

Diff for: edxp-core/src/main/cpp/main/src/jni/edxp_pending_hooks.h

+4
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,8 @@ namespace edxp {
1313

1414
void recordHooked(void* art_method);
1515

16+
void DonePendingHook(void *clazz);
17+
18+
bool IsMethodPending(void* art_method);
19+
1620
} // namespace edxp

Diff for: xposed-bridge/src/main/java/de/robv/android/xposed/PendingHooks.java

+5-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package de.robv.android.xposed;
22

33
import java.lang.reflect.Member;
4+
import java.lang.reflect.Method;
45
import java.util.Map;
56
import java.util.concurrent.ConcurrentHashMap;
67
import java.util.function.Function;
@@ -18,10 +19,11 @@ public synchronized static void hookPendingMethod(Class<?> clazz) {
1819
for (Map.Entry<Member, XposedBridge.AdditionalHookInfo> hook : sPendingHooks.get(clazz).entrySet()) {
1920
hookMethodNative(hook.getKey(), clazz, 0, hook.getValue());
2021
}
22+
sPendingHooks.remove(clazz);
2123
}
2224
}
2325

24-
public synchronized static void recordPendingMethod(Member hookMethod,
26+
public synchronized static void recordPendingMethod(Method hookMethod,
2527
XposedBridge.AdditionalHookInfo additionalInfo) {
2628
ConcurrentHashMap<Member, XposedBridge.AdditionalHookInfo> pending =
2729
sPendingHooks.computeIfAbsent(hookMethod.getDeclaringClass(),
@@ -33,12 +35,12 @@ public ConcurrentHashMap<Member, XposedBridge.AdditionalHookInfo> apply(Class<?>
3335
});
3436

3537
pending.put(hookMethod, additionalInfo);
36-
recordPendingMethodNative(hookMethod.getDeclaringClass());
38+
recordPendingMethodNative(hookMethod, hookMethod.getDeclaringClass());
3739
}
3840

3941
public synchronized void cleanUp() {
4042
sPendingHooks.clear();
4143
}
4244

43-
private static native void recordPendingMethodNative(Class clazz);
45+
private static native void recordPendingMethodNative(Method hookMethod, Class clazz);
4446
}

Diff for: xposed-bridge/src/main/java/de/robv/android/xposed/XposedBridge.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ public static XC_MethodHook.Unhook hookMethod(Member hookMethod, XC_MethodHook c
240240
if (reflectMethod != null) {
241241
hookMethodNative(reflectMethod, declaringClass, slot, additionalInfo);
242242
} else {
243-
PendingHooks.recordPendingMethod(hookMethod, additionalInfo);
243+
PendingHooks.recordPendingMethod((Method)hookMethod, additionalInfo);
244244
}
245245
}
246246

0 commit comments

Comments
 (0)