Add compatibility for the new version of LSPosed
This commit is contained in:
49
app/src/main/java/io/nekohasekai/sfa/xposed/HookInstaller.kt
Normal file
49
app/src/main/java/io/nekohasekai/sfa/xposed/HookInstaller.kt
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
package io.nekohasekai.sfa.xposed
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import io.nekohasekai.sfa.xposed.hooks.HookIConnectivityManagerOnTransact
|
||||||
|
import io.nekohasekai.sfa.xposed.hooks.hidevpn.ConnectivityServiceHookHelper
|
||||||
|
import io.nekohasekai.sfa.xposed.hooks.hidevpn.HookNetworkCapabilitiesWriteToParcel
|
||||||
|
import io.nekohasekai.sfa.xposed.hooks.hidevpn.HookNetworkInterfaceGetName
|
||||||
|
import io.nekohasekai.sfa.xposed.hooks.hidevpnapp.HookPackageManagerGetInstalledPackages
|
||||||
|
|
||||||
|
object HookInstaller {
|
||||||
|
|
||||||
|
private const val TAG = "XposedInit"
|
||||||
|
|
||||||
|
private val activityThreadClass by lazy { Class.forName("android.app.ActivityThread") }
|
||||||
|
private val currentActivityThreadMethod by lazy { activityThreadClass.getMethod("currentActivityThread") }
|
||||||
|
private val getSystemContextMethod by lazy { activityThreadClass.getMethod("getSystemContext") }
|
||||||
|
|
||||||
|
fun install(classLoader: ClassLoader) {
|
||||||
|
val systemContext = resolveSystemContext()
|
||||||
|
HookErrorStore.i(TAG, "handleSystemServerLoaded")
|
||||||
|
val hooks = arrayOf(
|
||||||
|
ConnectivityServiceHookHelper(classLoader),
|
||||||
|
HookIConnectivityManagerOnTransact(classLoader, systemContext),
|
||||||
|
HookPackageManagerGetInstalledPackages(classLoader),
|
||||||
|
HookNetworkCapabilitiesWriteToParcel(),
|
||||||
|
HookNetworkInterfaceGetName(classLoader),
|
||||||
|
)
|
||||||
|
|
||||||
|
hooks.forEach { hook ->
|
||||||
|
try {
|
||||||
|
hook.injectHook()
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
HookErrorStore.e(
|
||||||
|
TAG,
|
||||||
|
"Failed to inject ${hook.javaClass.simpleName}",
|
||||||
|
e,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun resolveSystemContext(): Context? = try {
|
||||||
|
val currentThread = currentActivityThreadMethod.invoke(null)
|
||||||
|
getSystemContextMethod.invoke(currentThread) as? Context
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
HookErrorStore.e(TAG, "resolveSystemContext failed", e)
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,54 +1,16 @@
|
|||||||
package io.nekohasekai.sfa.xposed
|
package io.nekohasekai.sfa.xposed
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import io.github.libxposed.api.XposedInterface
|
import io.github.libxposed.api.XposedInterface
|
||||||
import io.github.libxposed.api.XposedModule
|
import io.github.libxposed.api.XposedModule
|
||||||
import io.github.libxposed.api.XposedModuleInterface
|
import io.github.libxposed.api.XposedModuleInterface
|
||||||
import io.nekohasekai.sfa.xposed.hooks.HookIConnectivityManagerOnTransact
|
|
||||||
import io.nekohasekai.sfa.xposed.hooks.hidevpn.ConnectivityServiceHookHelper
|
|
||||||
import io.nekohasekai.sfa.xposed.hooks.hidevpn.HookNetworkCapabilitiesWriteToParcel
|
|
||||||
import io.nekohasekai.sfa.xposed.hooks.hidevpn.HookNetworkInterfaceGetName
|
|
||||||
import io.nekohasekai.sfa.xposed.hooks.hidevpnapp.HookPackageManagerGetInstalledPackages
|
|
||||||
|
|
||||||
class XposedInit(base: XposedInterface, param: XposedModuleInterface.ModuleLoadedParam) : XposedModule(base, param) {
|
class XposedInit(base: XposedInterface, param: XposedModuleInterface.ModuleLoadedParam) : XposedModule(base, param) {
|
||||||
|
|
||||||
private val activityThreadClass by lazy { Class.forName("android.app.ActivityThread") }
|
|
||||||
private val currentActivityThreadMethod by lazy { activityThreadClass.getMethod("currentActivityThread") }
|
|
||||||
private val getSystemContextMethod by lazy { activityThreadClass.getMethod("getSystemContext") }
|
|
||||||
|
|
||||||
override fun onSystemServerLoaded(param: XposedModuleInterface.SystemServerLoadedParam) {
|
override fun onSystemServerLoaded(param: XposedModuleInterface.SystemServerLoadedParam) {
|
||||||
val systemContext = resolveSystemContext()
|
HookInstaller.install(param.classLoader)
|
||||||
HookErrorStore.i("XposedInit", "handleSystemServerLoaded")
|
|
||||||
val hooks = arrayOf(
|
|
||||||
ConnectivityServiceHookHelper(param.classLoader),
|
|
||||||
HookIConnectivityManagerOnTransact(param.classLoader, systemContext),
|
|
||||||
HookPackageManagerGetInstalledPackages(param.classLoader),
|
|
||||||
HookNetworkCapabilitiesWriteToParcel(),
|
|
||||||
HookNetworkInterfaceGetName(param.classLoader),
|
|
||||||
)
|
|
||||||
|
|
||||||
hooks.forEach { hook ->
|
|
||||||
try {
|
|
||||||
hook.injectHook()
|
|
||||||
} catch (e: Throwable) {
|
|
||||||
HookErrorStore.e(
|
|
||||||
"XposedInit",
|
|
||||||
"Failed to inject ${hook.javaClass.simpleName}",
|
|
||||||
e,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val TAG = "sing-box-lsposed"
|
const val TAG = "sing-box-lsposed"
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun resolveSystemContext(): Context? = try {
|
|
||||||
val currentThread = currentActivityThreadMethod.invoke(null)
|
|
||||||
getSystemContextMethod.invoke(currentThread) as? Context
|
|
||||||
} catch (e: Throwable) {
|
|
||||||
HookErrorStore.e("XposedInit", "resolveSystemContext failed", e)
|
|
||||||
null
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
11
app/src/main/java/io/nekohasekai/sfa/xposed/XposedInit101.kt
Normal file
11
app/src/main/java/io/nekohasekai/sfa/xposed/XposedInit101.kt
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
package io.nekohasekai.sfa.xposed
|
||||||
|
|
||||||
|
import io.github.libxposed.api.XposedModule
|
||||||
|
import io.github.libxposed.api.XposedModuleInterface
|
||||||
|
|
||||||
|
class XposedInit101 : XposedModule() {
|
||||||
|
|
||||||
|
override fun onSystemServerStarting(param: XposedModuleInterface.SystemServerStartingParam) {
|
||||||
|
HookInstaller.install(param.classLoader)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1 +1,2 @@
|
|||||||
io.nekohasekai.sfa.xposed.XposedInit
|
io.nekohasekai.sfa.xposed.XposedInit
|
||||||
|
io.nekohasekai.sfa.xposed.XposedInit101
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
minApiVersion=100
|
minApiVersion=100
|
||||||
targetApiVersion=100
|
targetApiVersion=101
|
||||||
staticScope=true
|
staticScope=true
|
||||||
|
|||||||
@@ -21,9 +21,19 @@ import io.github.libxposed.api.utils.DexParser;
|
|||||||
*/
|
*/
|
||||||
public class XposedInterfaceWrapper implements XposedInterface {
|
public class XposedInterfaceWrapper implements XposedInterface {
|
||||||
|
|
||||||
private final XposedInterface mBase;
|
private volatile XposedInterface mBase;
|
||||||
|
|
||||||
XposedInterfaceWrapper(@NonNull XposedInterface base) {
|
public XposedInterfaceWrapper() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public XposedInterfaceWrapper(@NonNull XposedInterface base) {
|
||||||
|
mBase = base;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void attachFramework(@NonNull XposedInterface base) {
|
||||||
|
if (mBase != null) {
|
||||||
|
throw new IllegalStateException("Framework already attached");
|
||||||
|
}
|
||||||
mBase = base;
|
mBase = base;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,11 +9,16 @@ import androidx.annotation.NonNull;
|
|||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public abstract class XposedModule extends XposedInterfaceWrapper implements XposedModuleInterface {
|
public abstract class XposedModule extends XposedInterfaceWrapper implements XposedModuleInterface {
|
||||||
/**
|
/**
|
||||||
* Instantiates a new Xposed module.<br/>
|
* No-arg constructor for API 101 contract: the framework instantiates the module via
|
||||||
* When the module is loaded into the target process, the constructor will be called.
|
* {@code Class.getDeclaredConstructor()}, then calls {@link #attachFramework}.
|
||||||
*
|
*/
|
||||||
* @param base The implementation interface provided by the framework, should not be used by the module
|
public XposedModule() {
|
||||||
* @param param Information about the process in which the module is loaded
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Two-arg constructor for API 100 contract: the framework instantiates the module via
|
||||||
|
* {@code (XposedInterface, ModuleLoadedParam)} and attaches the framework base inline.
|
||||||
*/
|
*/
|
||||||
public XposedModule(@NonNull XposedInterface base, @NonNull ModuleLoadedParam param) {
|
public XposedModule(@NonNull XposedInterface base, @NonNull ModuleLoadedParam param) {
|
||||||
super(base);
|
super(base);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package io.github.libxposed.api;
|
package io.github.libxposed.api;
|
||||||
|
|
||||||
|
import android.app.AppComponentFactory;
|
||||||
import android.content.pm.ApplicationInfo;
|
import android.content.pm.ApplicationInfo;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
|
||||||
@@ -32,7 +33,7 @@ public interface XposedModuleInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wraps information about system server.
|
* Wraps information about system server. API 100 flavor.
|
||||||
*/
|
*/
|
||||||
interface SystemServerLoadedParam {
|
interface SystemServerLoadedParam {
|
||||||
/**
|
/**
|
||||||
@@ -44,6 +45,26 @@ public interface XposedModuleInterface {
|
|||||||
ClassLoader getClassLoader();
|
ClassLoader getClassLoader();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wraps information about system server. API 101 flavor.
|
||||||
|
*/
|
||||||
|
interface SystemServerStartingParam {
|
||||||
|
@NonNull
|
||||||
|
ClassLoader getClassLoader();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wraps information about a package whose classloader is ready. API 101.
|
||||||
|
*/
|
||||||
|
interface PackageReadyParam extends PackageLoadedParam {
|
||||||
|
@NonNull
|
||||||
|
ClassLoader getClassLoader();
|
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.P)
|
||||||
|
@NonNull
|
||||||
|
AppComponentFactory getAppComponentFactory();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wraps information about the package being loaded.
|
* Wraps information about the package being loaded.
|
||||||
*/
|
*/
|
||||||
@@ -99,10 +120,28 @@ public interface XposedModuleInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets notified when the system server is loaded.
|
* Gets notified when the system server is loaded. API 100.
|
||||||
*
|
*
|
||||||
* @param param Information about system server
|
* @param param Information about system server
|
||||||
*/
|
*/
|
||||||
default void onSystemServerLoaded(@NonNull SystemServerLoadedParam param) {
|
default void onSystemServerLoaded(@NonNull SystemServerLoadedParam param) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* API 101: invoked once per process after the module instance is attached.
|
||||||
|
*/
|
||||||
|
default void onModuleLoaded(@NonNull ModuleLoadedParam param) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* API 101: invoked when a package's classloader is ready.
|
||||||
|
*/
|
||||||
|
default void onPackageReady(@NonNull PackageReadyParam param) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* API 101: replaces {@link #onSystemServerLoaded(SystemServerLoadedParam)}.
|
||||||
|
*/
|
||||||
|
default void onSystemServerStarting(@NonNull SystemServerStartingParam param) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user