[core] Refactor pending hook (#1125)

This commit is contained in:
LoveSy 2021-09-18 12:45:15 +08:00 committed by GitHub
parent acbd6adc77
commit 5c5e1755d6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 30 additions and 31 deletions

View File

@ -26,7 +26,7 @@ import java.lang.reflect.Method;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
public class LspHooker { public class LspHooker {
private final XposedBridge.AdditionalHookInfo additionalInfo; public final XposedBridge.AdditionalHookInfo additionalInfo;
private final Executable method; private final Executable method;
private final Method backup; private final Method backup;

View File

@ -26,35 +26,26 @@ import org.lsposed.lspd.yahfa.hooker.YahfaHooker;
import java.lang.reflect.Executable; import java.lang.reflect.Executable;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
public final class PendingHooks { public final class PendingHooks {
// GuardedBy("PendingHooks.class")
private static final ConcurrentHashMap<Class<?>, ConcurrentHashMap<Executable, XposedBridge.AdditionalHookInfo>> private static final ConcurrentHashMap<Class<?>, ConcurrentHashMap<Executable, XposedBridge.AdditionalHookInfo>>
sPendingHooks = new ConcurrentHashMap<>(); sPendingHooks = new ConcurrentHashMap<>();
public synchronized static void hookPendingMethod(Class<?> clazz) { public static void hookPendingMethod(Class<?> clazz) {
if (sPendingHooks.containsKey(clazz)) { var record = sPendingHooks.remove(clazz);
for (Map.Entry<Executable, XposedBridge.AdditionalHookInfo> hook : sPendingHooks.get(clazz).entrySet()) { if (record != null) {
for (var hook : record.entrySet()) {
YahfaHooker.hookMethod(hook.getKey(), hook.getValue()); YahfaHooker.hookMethod(hook.getKey(), hook.getValue());
} }
sPendingHooks.remove(clazz);
} }
} }
public synchronized static void recordPendingMethod(Method hookMethod, public static void recordPendingMethod(Method hookMethod,
XposedBridge.AdditionalHookInfo additionalInfo) { XposedBridge.AdditionalHookInfo additionalInfo) {
ConcurrentHashMap<Executable, XposedBridge.AdditionalHookInfo> pending = var pending = sPendingHooks.computeIfAbsent(hookMethod.getDeclaringClass(), aClass -> new ConcurrentHashMap<>());
sPendingHooks.computeIfAbsent(hookMethod.getDeclaringClass(), aClass -> new ConcurrentHashMap<>());
pending.put(hookMethod, additionalInfo); pending.put(hookMethod, additionalInfo);
recordPendingMethodNative(hookMethod, hookMethod.getDeclaringClass()); recordPendingMethodNative(hookMethod, hookMethod.getDeclaringClass());
} }
public synchronized void cleanUp() {
sPendingHooks.clear();
}
} }

View File

@ -28,32 +28,40 @@ import java.lang.reflect.Member;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import de.robv.android.xposed.LspHooker; import de.robv.android.xposed.LspHooker;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedBridge; import de.robv.android.xposed.XposedBridge;
public final class DynamicBridge { public final class DynamicBridge {
private static final ConcurrentHashMap<Executable, LspHooker> hookedInfo = new ConcurrentHashMap<>(); private static final ConcurrentHashMap<Executable, LspHooker> hookedInfo = new ConcurrentHashMap<>();
private static final ConcurrentHashMap<Executable, Object> lockers = new ConcurrentHashMap<>();
public static synchronized void hookMethod(Executable hookMethod, XposedBridge.AdditionalHookInfo additionalHookInfo) { public static void hookMethod(Executable hookMethod, XposedBridge.AdditionalHookInfo additionalHookInfo) {
Utils.logD("hooking " + hookMethod); Utils.logD("hooking " + hookMethod);
if (hookedInfo.containsKey(hookMethod)) { synchronized (lockers.computeIfAbsent(hookMethod, (m) -> new Object())) {
Utils.logW("already hook method:" + hookMethod, new IllegalStateException()); var hooker = hookedInfo.getOrDefault(hookMethod, null);
return; if (hooker == null) {
} Utils.logD("start to generate class for: " + hookMethod);
try {
Utils.logD("start to generate class for: " + hookMethod); final HookerDexMaker dexMaker = new HookerDexMaker();
try { dexMaker.start(hookMethod, additionalHookInfo);
final HookerDexMaker dexMaker = new HookerDexMaker(); hookedInfo.put(hookMethod, dexMaker.getHooker());
dexMaker.start(hookMethod, additionalHookInfo); } catch (Throwable e) {
hookedInfo.put(hookMethod, dexMaker.getHooker()); Utils.logE("error occur when generating dex.", e);
} catch (Throwable e) { }
Utils.logE("error occur when generating dex.", e); } else {
for (var callback : additionalHookInfo.callbacks.getSnapshot())
hooker.additionalInfo.callbacks.add((XC_MethodHook) callback);
}
} }
} }
public static Object invokeOriginalMethod(Member method, Object thisObject, Object[] args) public static Object invokeOriginalMethod(Member method, Object thisObject, Object[] args)
throws InvocationTargetException, IllegalAccessException { throws InvocationTargetException, IllegalAccessException {
LspHooker hooker = hookedInfo.get(method); if (!(method instanceof Executable)) {
throw new IllegalArgumentException("Only methods or constructors can be invoked.");
}
LspHooker hooker = hookedInfo.getOrDefault(method, null);
if (hooker == null) { if (hooker == null) {
throw new IllegalStateException("method not hooked, cannot call original method."); throw new IllegalStateException("method not hooked, cannot call original method.");
} }