Load module context
This commit is contained in:
parent
a2be0bd030
commit
14f31b604a
|
|
@ -221,7 +221,7 @@ public final class XposedInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void loadModules() {
|
public static void loadModules() {
|
||||||
var moduleList = serviceClient.getModulesList();
|
var moduleList = serviceClient.getLegacyModulesList();
|
||||||
moduleList.forEach(module -> {
|
moduleList.forEach(module -> {
|
||||||
var apk = module.apkPath;
|
var apk = module.apkPath;
|
||||||
var name = module.packageName;
|
var name = module.packageName;
|
||||||
|
|
@ -286,7 +286,7 @@ public final class XposedInit {
|
||||||
* in <code>assets/xposed_init</code>.
|
* in <code>assets/xposed_init</code>.
|
||||||
*/
|
*/
|
||||||
private static boolean loadModule(String name, String apk, PreLoadedApk file) {
|
private static boolean loadModule(String name, String apk, PreLoadedApk file) {
|
||||||
Log.i(TAG, "Loading module " + name + " from " + apk);
|
Log.i(TAG, "Loading legacy module " + name + " from " + apk);
|
||||||
|
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
var abis = Process.is64Bit() ? Build.SUPPORTED_64_BIT_ABIS : Build.SUPPORTED_32_BIT_ABIS;
|
var abis = Process.is64Bit() ? Build.SUPPORTED_64_BIT_ABIS : Build.SUPPORTED_32_BIT_ABIS;
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,15 @@ public class ApplicationServiceClient implements ILSPApplicationService, IBinder
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Module> getLegacyModulesList() {
|
||||||
|
try {
|
||||||
|
return service.getLegacyModulesList();
|
||||||
|
} catch (RemoteException | NullPointerException ignored) {
|
||||||
|
}
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Module> getModulesList() {
|
public List<Module> getModulesList() {
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ import android.content.res.CompatibilityInfo;
|
||||||
import com.android.internal.os.ZygoteInit;
|
import com.android.internal.os.ZygoteInit;
|
||||||
|
|
||||||
import org.lsposed.lspd.deopt.PrebuiltMethodsDeopter;
|
import org.lsposed.lspd.deopt.PrebuiltMethodsDeopter;
|
||||||
|
import org.lsposed.lspd.hooker.AttachHooker;
|
||||||
import org.lsposed.lspd.hooker.CrashDumpHooker;
|
import org.lsposed.lspd.hooker.CrashDumpHooker;
|
||||||
import org.lsposed.lspd.hooker.HandleSystemServerProcessHooker;
|
import org.lsposed.lspd.hooker.HandleSystemServerProcessHooker;
|
||||||
import org.lsposed.lspd.hooker.LoadedApkCtorHooker;
|
import org.lsposed.lspd.hooker.LoadedApkCtorHooker;
|
||||||
|
|
@ -59,6 +60,8 @@ public class Startup {
|
||||||
ActivityThread.class, ApplicationInfo.class, CompatibilityInfo.class,
|
ActivityThread.class, ApplicationInfo.class, CompatibilityInfo.class,
|
||||||
ClassLoader.class, boolean.class, boolean.class, boolean.class,
|
ClassLoader.class, boolean.class, boolean.class, boolean.class,
|
||||||
new LoadedApkCtorHooker());
|
new LoadedApkCtorHooker());
|
||||||
|
XposedHelpers.findAndHookMethod(ActivityThread.class, "attach", boolean.class,
|
||||||
|
long.class, new AttachHooker());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void bootstrapXposed() {
|
public static void bootstrapXposed() {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
package org.lsposed.lspd.hooker;
|
||||||
|
|
||||||
|
import static org.lsposed.lspd.core.ApplicationServiceClient.serviceClient;
|
||||||
|
|
||||||
|
import android.app.ActivityThread;
|
||||||
|
import android.app.LoadedApk;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.ContextParams;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.Process;
|
||||||
|
|
||||||
|
import org.lsposed.lspd.util.Hookers;
|
||||||
|
import org.lsposed.lspd.util.LspModuleClassLoader;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
import de.robv.android.xposed.XC_MethodHook;
|
||||||
|
import de.robv.android.xposed.XposedHelpers;
|
||||||
|
import de.robv.android.xposed.XposedInit;
|
||||||
|
|
||||||
|
public class AttachHooker extends XC_MethodHook {
|
||||||
|
@Override
|
||||||
|
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
|
||||||
|
var at = (ActivityThread) param.thisObject;
|
||||||
|
var moduleList = serviceClient.getModulesList();
|
||||||
|
moduleList.forEach(module -> {
|
||||||
|
try {
|
||||||
|
XposedInit.getLoadedModules().add(module.packageName);
|
||||||
|
var loadedApk = at.getPackageInfoNoCheck(module.applicationInfo, null);
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
var abis = Process.is64Bit() ? Build.SUPPORTED_64_BIT_ABIS : Build.SUPPORTED_32_BIT_ABIS;
|
||||||
|
for (String abi : abis) {
|
||||||
|
sb.append(module.apkPath).append("!/lib/").append(abi).append(File.pathSeparator);
|
||||||
|
}
|
||||||
|
var librarySearchPath = sb.toString();
|
||||||
|
|
||||||
|
var initLoader = XposedInit.class.getClassLoader();
|
||||||
|
var mcl = LspModuleClassLoader.loadApk(module.apkPath, module.file.preLoadedDexes, librarySearchPath, initLoader);
|
||||||
|
XposedHelpers.setObjectField(loadedApk, "mClassLoader", mcl);
|
||||||
|
var c = Class.forName("android.app.ContextImpl");
|
||||||
|
var ctor = c.getDeclaredConstructors()[0];
|
||||||
|
ctor.setAccessible(true);
|
||||||
|
var args = new Object[ctor.getParameterTypes().length];
|
||||||
|
for (int i = 0; i < ctor.getParameterTypes().length; ++i) {
|
||||||
|
if (ctor.getParameterTypes()[i] == LoadedApk.class) {
|
||||||
|
args[i] = loadedApk;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||||
|
if (ctor.getParameterTypes()[i] == ContextParams.class) {
|
||||||
|
args[i] = new ContextParams.Builder().build();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ctor.getParameterTypes()[i] == ActivityThread.class) {
|
||||||
|
args[i] = at;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (ctor.getParameterTypes()[i] == int.class) {
|
||||||
|
args[i] = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
args[i] = null;
|
||||||
|
}
|
||||||
|
var ctx = (Context) ctor.newInstance(args);
|
||||||
|
Hookers.logD("Loaded module " + module.packageName + ": " + ctx);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
Hookers.logE("Loading module " + module.packageName, e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -40,6 +40,9 @@ public class LoadedApkCtorHooker extends XC_MethodHook {
|
||||||
try {
|
try {
|
||||||
LoadedApk loadedApk = (LoadedApk) param.thisObject;
|
LoadedApk loadedApk = (LoadedApk) param.thisObject;
|
||||||
String packageName = loadedApk.getPackageName();
|
String packageName = loadedApk.getPackageName();
|
||||||
|
if (XposedInit.getLoadedModules().contains(packageName)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
Object mAppDir = XposedHelpers.getObjectField(loadedApk, "mAppDir");
|
Object mAppDir = XposedHelpers.getObjectField(loadedApk, "mAppDir");
|
||||||
Hookers.logD("LoadedApk#<init> ends: " + mAppDir);
|
Hookers.logD("LoadedApk#<init> ends: " + mAppDir);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -368,9 +368,11 @@ public class ConfigFileManager {
|
||||||
// TODO: we can store more info like api version, module description, etc. in META-INF
|
// TODO: we can store more info like api version, module description, etc. in META-INF
|
||||||
readName(apkFile, "META-INF/xposed/xposed_init", moduleClassNames);
|
readName(apkFile, "META-INF/xposed/xposed_init", moduleClassNames);
|
||||||
if (moduleClassNames.isEmpty()) {
|
if (moduleClassNames.isEmpty()) {
|
||||||
|
file.usingContext = false;
|
||||||
readName(apkFile, "assets/xposed_init", moduleClassNames);
|
readName(apkFile, "assets/xposed_init", moduleClassNames);
|
||||||
readName(apkFile, "assets/native_init", moduleLibraryNames);
|
readName(apkFile, "assets/native_init", moduleLibraryNames);
|
||||||
} else {
|
} else {
|
||||||
|
file.usingContext = true;
|
||||||
readName(apkFile, "META-INF/xposed/native_init", moduleLibraryNames);
|
readName(apkFile, "META-INF/xposed/native_init", moduleLibraryNames);
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class LSPApplicationService extends ILSPApplicationService.Stub {
|
public class LSPApplicationService extends ILSPApplicationService.Stub {
|
||||||
final static int DEX_TRANSACTION_CODE = 1310096052;
|
final static int DEX_TRANSACTION_CODE = 1310096052;
|
||||||
|
|
@ -115,8 +116,7 @@ public class LSPApplicationService extends ILSPApplicationService.Stub {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private List<Module> getAllModulesList() throws RemoteException {
|
||||||
public List<Module> getModulesList() throws RemoteException {
|
|
||||||
var processInfo = ensureRegistered();
|
var processInfo = ensureRegistered();
|
||||||
if (processInfo.uid == 1000 && processInfo.processName.equals("android")) {
|
if (processInfo.uid == 1000 && processInfo.processName.equals("android")) {
|
||||||
return ConfigManager.getInstance().getModulesForSystemServer();
|
return ConfigManager.getInstance().getModulesForSystemServer();
|
||||||
|
|
@ -126,6 +126,16 @@ public class LSPApplicationService extends ILSPApplicationService.Stub {
|
||||||
return ConfigManager.getInstance().getModulesForProcess(processInfo.processName, processInfo.uid);
|
return ConfigManager.getInstance().getModulesForProcess(processInfo.processName, processInfo.uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Module> getLegacyModulesList() throws RemoteException {
|
||||||
|
return getAllModulesList().stream().filter(m -> !m.file.usingContext).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Module> getModulesList() throws RemoteException {
|
||||||
|
return getAllModulesList().stream().filter(m -> m.file.usingContext).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getPrefsPath(String packageName) throws RemoteException {
|
public String getPrefsPath(String packageName) throws RemoteException {
|
||||||
ensureRegistered();
|
ensureRegistered();
|
||||||
|
|
|
||||||
|
|
@ -4,4 +4,5 @@ parcelable PreLoadedApk {
|
||||||
List<SharedMemory> preLoadedDexes;
|
List<SharedMemory> preLoadedDexes;
|
||||||
List<String> moduleClassNames;
|
List<String> moduleClassNames;
|
||||||
List<String> moduleLibraryNames;
|
List<String> moduleLibraryNames;
|
||||||
|
boolean usingContext;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@ import org.lsposed.lspd.models.Module;
|
||||||
interface ILSPApplicationService {
|
interface ILSPApplicationService {
|
||||||
IBinder requestModuleBinder(String name);
|
IBinder requestModuleBinder(String name);
|
||||||
|
|
||||||
|
List<Module> getLegacyModulesList();
|
||||||
|
|
||||||
List<Module> getModulesList();
|
List<Module> getModulesList();
|
||||||
|
|
||||||
String getPrefsPath(String packageName);
|
String getPrefsPath(String packageName);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue