Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions core/src/main/java/org/lsposed/lspd/impl/LSPosedContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,27 @@ public <T> MethodUnhooker<Constructor<T>> hook(@NonNull Constructor<T> origin, i
return LSPosedBridge.doHook(origin, priority, hooker);
}

@Override
@NonNull
public <T> MethodUnhooker<Constructor<T>> hookClassInitializer(@NonNull Class<T> origin, @NonNull Class<? extends Hooker> hooker) {
return hookClassInitializer(origin, PRIORITY_DEFAULT, hooker);
}

@Override
@NonNull
@SuppressWarnings({"unchecked", "rawtypes"})
public <T> MethodUnhooker<Constructor<T>> hookClassInitializer(@NonNull Class<T> origin, int priority, @NonNull Class<? extends Hooker> hooker) {
Method staticInitializer = HookBridge.getStaticInitializer(origin);

// The class might not have a static initializer block
if (staticInitializer == null) {
throw new IllegalArgumentException("Class " + origin.getName() + " has no static initializer");
}

// Use the existing doHook logic. It will return a MethodUnhooker<Method>.
return (MethodUnhooker) LSPosedBridge.doHook(staticInitializer, priority, hooker);
}

private static boolean doDeoptimize(@NonNull Executable method) {
if (Modifier.isAbstract(method.getModifiers())) {
throw new IllegalArgumentException("Cannot deoptimize abstract methods: " + method);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.lsposed.lspd.nativebridge;

import java.lang.reflect.Executable;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;

import dalvik.annotation.optimization.FastNative;
Expand All @@ -25,4 +26,12 @@ public class HookBridge {
public static native boolean setTrusted(Object cookie);

public static native Object[][] callbackSnapshot(Class<?> hooker_callback, Executable method);

/**
* Retrieves the static initializer (<clinit>) of a class as a Method object.
* Standard Java reflection cannot access this.
* @param clazz The class to inspect.
* @return A Method object for the static initializer, or null if it doesn't exist.
*/
public static native Method getStaticInitializer(Class<?> clazz);
}
16 changes: 16 additions & 0 deletions core/src/main/jni/src/jni/hook_bridge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,21 @@ LSP_DEF_NATIVE_METHOD(jobjectArray, HookBridge, callbackSnapshot, jclass callbac
return res;
}

LSP_DEF_NATIVE_METHOD(jobject, HookBridge, getStaticInitializer, jclass target_class) {
// <clinit> is the internal name for a static initializer.
// Its signature is always ()V (no arguments, void return).
jmethodID mid = env->GetStaticMethodID(target_class, "<clinit>", "()V");
if (!mid) {
// If GetStaticMethodID fails, it throws an exception.
// We clear it and return null to let the Java side handle it gracefully.
env->ExceptionClear();
return nullptr;
}
// Convert the method ID to a java.lang.reflect.Method object.
// The last parameter must be JNI_TRUE because it's a static method.
return env->ToReflectedMethod(target_class, mid, JNI_TRUE);
}

static JNINativeMethod gMethods[] = {
LSP_NATIVE_METHOD(HookBridge, hookMethod, "(ZLjava/lang/reflect/Executable;Ljava/lang/Class;ILjava/lang/Object;)Z"),
LSP_NATIVE_METHOD(HookBridge, unhookMethod, "(ZLjava/lang/reflect/Executable;Ljava/lang/Object;)Z"),
Expand All @@ -332,6 +347,7 @@ static JNINativeMethod gMethods[] = {
LSP_NATIVE_METHOD(HookBridge, instanceOf, "(Ljava/lang/Object;Ljava/lang/Class;)Z"),
LSP_NATIVE_METHOD(HookBridge, setTrusted, "(Ljava/lang/Object;)Z"),
LSP_NATIVE_METHOD(HookBridge, callbackSnapshot, "(Ljava/lang/Class;Ljava/lang/reflect/Executable;)[[Ljava/lang/Object;"),
LSP_NATIVE_METHOD(HookBridge, getStaticInitializer, "(Ljava/lang/Class;)Ljava/lang/reflect/Method;"),
};

void RegisterHookBridge(JNIEnv *env) {
Expand Down