Optimize module loading under dynamic-modules mode

by only loading newly added or updated modules
This commit is contained in:
solohsu 2019-06-19 15:34:51 +08:00
parent be9105317f
commit f6d2e3b62f
18 changed files with 173 additions and 78 deletions

View File

@ -1,4 +1,4 @@
version: '0.4.4.6_alpha({build})' version: '0.4.4.7_alpha({build})'
environment: environment:
ANDROID_HOME: C:\android-sdk-windows ANDROID_HOME: C:\android-sdk-windows

View File

@ -72,10 +72,10 @@ public abstract class BaseRouter implements Router {
} }
} }
public void loadModulesSafely(boolean isInZygote) { public void loadModulesSafely(boolean isInZygote, boolean callInitZygote) {
try { try {
// FIXME some coredomain app can't reading modules.list // FIXME some coredomain app can't reading modules.list
XposedInit.loadModules(isInZygote); XposedInit.loadModules(isInZygote, callInitZygote);
} catch (Exception exception) { } catch (Exception exception) {
Utils.logE("error loading module list", exception); Utils.logE("error loading module list", exception);
} }

View File

@ -84,8 +84,7 @@ public class BlackWhiteListProxy extends BaseProxy {
// because installed hooks would be propagated to all child processes of zygote // because installed hooks would be propagated to all child processes of zygote
mRouter.startWorkAroundHook(); mRouter.startWorkAroundHook();
// loadModules once for all child processes of zygote // loadModules once for all child processes of zygote
// TODO maybe just save initZygote callbacks and call them when whitelisted process forked? mRouter.loadModulesSafely(true, false);
mRouter.loadModulesSafely(true);
} }
private void onForkPostCommon(boolean isSystemServer, String appDataDir, String niceName) { private void onForkPostCommon(boolean isSystemServer, String appDataDir, String niceName) {
@ -104,12 +103,15 @@ public class BlackWhiteListProxy extends BaseProxy {
mRouter.prepare(isSystemServer); mRouter.prepare(isSystemServer);
PrebuiltMethodsDeopter.deoptBootMethods(); PrebuiltMethodsDeopter.deoptBootMethods();
mRouter.installBootstrapHooks(isSystemServer); mRouter.installBootstrapHooks(isSystemServer);
// under dynamic modules mode, don't call initZygote when loadModule
// cuz loaded module won't has that chance to do it
if (isDynamicModulesMode) { if (isDynamicModulesMode) {
mRouter.loadModulesSafely(false); mRouter.loadModulesSafely(false, false);
} else {
XposedBridge.callInitZygotes();
XposedBridge.clearInitZygotes(); // one-time use
} }
// call all initZygote callbacks
XposedBridge.callInitZygotes();
mRouter.onForkFinish(); mRouter.onForkFinish();
} }
@ -131,8 +133,6 @@ public class BlackWhiteListProxy extends BaseProxy {
} }
private static void onBlackListed() { private static void onBlackListed() {
XposedBridge.clearLoadedPackages(); XposedBridge.clearAllCallbacks();
XposedBridge.clearInitPackageResources();
XposedBridge.clearInitZygotes();
} }
} }

View File

@ -25,7 +25,7 @@ public class NormalProxy extends BaseProxy {
// install bootstrap hooks for secondary zygote // install bootstrap hooks for secondary zygote
mRouter.installBootstrapHooks(false); mRouter.installBootstrapHooks(false);
// only load modules for secondary zygote // only load modules for secondary zygote
mRouter.loadModulesSafely(true); mRouter.loadModulesSafely(true, true);
} }
public void forkAndSpecializePost(int pid, String appDataDir, String niceName) { public void forkAndSpecializePost(int pid, String appDataDir, String niceName) {
@ -35,7 +35,7 @@ public class NormalProxy extends BaseProxy {
mRouter.prepare(false); mRouter.prepare(false);
mRouter.onEnterChildProcess(); mRouter.onEnterChildProcess();
// load modules for each app process on its forked if dynamic modules mode is on // load modules for each app process on its forked if dynamic modules mode is on
mRouter.loadModulesSafely(false); mRouter.loadModulesSafely(false, true);
mRouter.onForkFinish(); mRouter.onForkFinish();
} }
@ -53,7 +53,7 @@ public class NormalProxy extends BaseProxy {
// loadModules have to be executed in zygote even isDynamicModules is false // loadModules have to be executed in zygote even isDynamicModules is false
// because if not global hooks installed in initZygote might not be // because if not global hooks installed in initZygote might not be
// propagated to processes not forked via forkAndSpecialize // propagated to processes not forked via forkAndSpecialize
mRouter.loadModulesSafely(true); mRouter.loadModulesSafely(true, true);
} }
public void forkSystemServerPost(int pid) { public void forkSystemServerPost(int pid) {
@ -63,7 +63,9 @@ public class NormalProxy extends BaseProxy {
mRouter.prepare(true); mRouter.prepare(true);
mRouter.onEnterChildProcess(); mRouter.onEnterChildProcess();
// reload module list if dynamic mode is on // reload module list if dynamic mode is on
mRouter.loadModulesSafely(false); if (ConfigManager.isDynamicModulesEnabled()) {
mRouter.loadModulesSafely(false, true);
}
mRouter.onForkFinish(); mRouter.onForkFinish();
} }

View File

@ -10,7 +10,7 @@ public interface Router {
void installBootstrapHooks(boolean isSystem); void installBootstrapHooks(boolean isSystem);
void loadModulesSafely(boolean isInZygote); void loadModulesSafely(boolean isInZygote, boolean callInitZygote);
void startBootstrapHook(boolean isSystem); void startBootstrapHook(boolean isSystem);

View File

@ -4,7 +4,7 @@ import org.gradle.internal.os.OperatingSystem
apply plugin: 'com.android.library' apply plugin: 'com.android.library'
// Values set here will be overriden by AppVeyor, feel free to modify during development. // Values set here will be overriden by AppVeyor, feel free to modify during development.
def buildVersionName = 'v0.4.4.6_alpha' def buildVersionName = 'v0.4.4.7_alpha'
def buildVersionCode = 10000 def buildVersionCode = 10000
if (System.env.APPVEYOR_BUILD_VERSION != null) { if (System.env.APPVEYOR_BUILD_VERSION != null) {

View File

@ -120,6 +120,7 @@ namespace edxp {
variant_ = static_cast<Variant>(variant); variant_ = static_cast<Variant>(variant);
} }
} }
LOGI("EdxpVariant: %d", variant_);
initialized_ = true; initialized_ = true;

View File

@ -62,7 +62,6 @@ public class SandHookRouter extends BaseRouter {
public void injectConfig() { public void injectConfig() {
EdXpConfigGlobal.sConfig = new SandHookEdxpConfig(); EdXpConfigGlobal.sConfig = new SandHookEdxpConfig();
EdXpConfigGlobal.sHookProvider = new SandHookProvider(); EdXpConfigGlobal.sHookProvider = new SandHookProvider();
XposedBridge.log("using HookProvider: " + EdXpConfigGlobal.sHookProvider.getClass().getName());
} }
} }

View File

@ -1,22 +1,11 @@
package com.elderdrivers.riru.edxp.whale.core; package com.elderdrivers.riru.edxp.whale.core;
import android.app.ActivityThread;
import android.content.pm.ApplicationInfo;
import android.content.res.CompatibilityInfo;
import com.elderdrivers.riru.edxp._hooker.impl.HandleBindApp;
import com.elderdrivers.riru.edxp._hooker.impl.LoadedApkCstr;
import com.elderdrivers.riru.edxp._hooker.yahfa.HandleBindAppHooker;
import com.elderdrivers.riru.edxp._hooker.yahfa.LoadedApkConstructorHooker;
import com.elderdrivers.riru.edxp.config.EdXpConfigGlobal; import com.elderdrivers.riru.edxp.config.EdXpConfigGlobal;
import com.elderdrivers.riru.edxp.framework.Zygote; import com.elderdrivers.riru.edxp.framework.Zygote;
import com.elderdrivers.riru.edxp.proxy.BaseRouter; import com.elderdrivers.riru.edxp.proxy.BaseRouter;
import com.elderdrivers.riru.edxp.whale.config.WhaleEdxpConfig; import com.elderdrivers.riru.edxp.whale.config.WhaleEdxpConfig;
import com.elderdrivers.riru.edxp.whale.config.WhaleHookProvider; import com.elderdrivers.riru.edxp.whale.config.WhaleHookProvider;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;
public class WhaleRouter extends BaseRouter { public class WhaleRouter extends BaseRouter {
public void onEnterChildProcess() { public void onEnterChildProcess() {
@ -27,7 +16,6 @@ public class WhaleRouter extends BaseRouter {
BaseRouter.useXposedApi = true; BaseRouter.useXposedApi = true;
EdXpConfigGlobal.sConfig = new WhaleEdxpConfig(); EdXpConfigGlobal.sConfig = new WhaleEdxpConfig();
EdXpConfigGlobal.sHookProvider = new WhaleHookProvider(); EdXpConfigGlobal.sHookProvider = new WhaleHookProvider();
XposedBridge.log("using HookProvider: " + EdXpConfigGlobal.sHookProvider.getClass().getName());
Zygote.allowFileAcrossFork("/system/lib/libwhale.edxp.so"); Zygote.allowFileAcrossFork("/system/lib/libwhale.edxp.so");
Zygote.allowFileAcrossFork("/system/lib64/libwhale.edxp.so"); Zygote.allowFileAcrossFork("/system/lib64/libwhale.edxp.so");
Zygote.allowFileAcrossFork("/system/lib/libart.so"); Zygote.allowFileAcrossFork("/system/lib/libart.so");

View File

@ -6,8 +6,6 @@ import com.elderdrivers.riru.edxp.yahfa.config.YahfaEdxpConfig;
import com.elderdrivers.riru.edxp.yahfa.config.YahfaHookProvider; import com.elderdrivers.riru.edxp.yahfa.config.YahfaHookProvider;
import com.elderdrivers.riru.edxp.yahfa.dexmaker.DynamicBridge; import com.elderdrivers.riru.edxp.yahfa.dexmaker.DynamicBridge;
import de.robv.android.xposed.XposedBridge;
public class YahfaRouter extends BaseRouter { public class YahfaRouter extends BaseRouter {
public void onEnterChildProcess() { public void onEnterChildProcess() {
@ -17,7 +15,6 @@ public class YahfaRouter extends BaseRouter {
public void injectConfig() { public void injectConfig() {
EdXpConfigGlobal.sConfig = new YahfaEdxpConfig(); EdXpConfigGlobal.sConfig = new YahfaEdxpConfig();
EdXpConfigGlobal.sHookProvider = new YahfaHookProvider(); EdXpConfigGlobal.sHookProvider = new YahfaHookProvider();
XposedBridge.log("using HookProvider: " + EdXpConfigGlobal.sHookProvider.getClass().getName());
} }
} }

View File

@ -0,0 +1,6 @@
package de.robv.android.xposed;
public interface IModuleContext {
String getApkPath();
}

View File

@ -25,12 +25,21 @@ public interface IXposedHookInitPackageResources extends IXposedMod {
/** @hide */ /** @hide */
final class Wrapper extends XC_InitPackageResources { final class Wrapper extends XC_InitPackageResources {
private final IXposedHookInitPackageResources instance; private final IXposedHookInitPackageResources instance;
public Wrapper(IXposedHookInitPackageResources instance) { private final String apkPath;
public Wrapper(IXposedHookInitPackageResources instance, String apkPath) {
this.instance = instance; this.instance = instance;
this.apkPath = apkPath;
} }
@Override @Override
public void handleInitPackageResources(InitPackageResourcesParam resparam) throws Throwable { public void handleInitPackageResources(InitPackageResourcesParam resparam) throws Throwable {
instance.handleInitPackageResources(resparam); instance.handleInitPackageResources(resparam);
} }
@Override
public String getApkPath() {
return apkPath;
}
} }
} }

View File

@ -26,12 +26,20 @@ public interface IXposedHookLoadPackage extends IXposedMod {
/** @hide */ /** @hide */
final class Wrapper extends XC_LoadPackage { final class Wrapper extends XC_LoadPackage {
private final IXposedHookLoadPackage instance; private final IXposedHookLoadPackage instance;
public Wrapper(IXposedHookLoadPackage instance) { private final String apkPath;
public Wrapper(IXposedHookLoadPackage instance, String apkPath) {
this.instance = instance; this.instance = instance;
this.apkPath = apkPath;
} }
@Override @Override
public void handleLoadPackage(LoadPackageParam lpparam) throws Throwable { public void handleLoadPackage(LoadPackageParam lpparam) throws Throwable {
instance.handleLoadPackage(lpparam); instance.handleLoadPackage(lpparam);
} }
@Override
public String getApkPath() {
return apkPath;
}
} }
} }

View File

@ -62,5 +62,10 @@ public interface IXposedHookZygoteInit extends IXposedMod {
// cause startupParam info is generated and saved along with instance here // cause startupParam info is generated and saved along with instance here
instance.initZygote(this.startupParam); instance.initZygote(this.startupParam);
} }
@Override
public String getApkPath() {
return startupParam.modulePath;
}
} }
} }

View File

@ -446,6 +446,12 @@ public final class XposedBridge {
XCallback.callAll(new IXposedHookZygoteInit.StartupParam(sInitZygoteCallbacks)); XCallback.callAll(new IXposedHookZygoteInit.StartupParam(sInitZygoteCallbacks));
} }
public static void clearAllCallbacks() {
clearLoadedPackages();
clearInitPackageResources();
clearInitZygotes();
}
/** /**
* Intercept every call to the specified method and call a handler function instead. * Intercept every call to the specified method and call a handler function instead.
* @param method The method to intercept * @param method The method to intercept

View File

@ -11,6 +11,7 @@ import android.os.Build;
import android.os.IBinder; import android.os.IBinder;
import android.os.Process; import android.os.Process;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log; import android.util.Log;
import com.android.internal.os.ZygoteInit; import com.android.internal.os.ZygoteInit;
@ -27,6 +28,7 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipFile; import java.util.zip.ZipFile;
@ -34,11 +36,17 @@ import java.util.zip.ZipFile;
import dalvik.system.DexFile; import dalvik.system.DexFile;
import dalvik.system.PathClassLoader; import dalvik.system.PathClassLoader;
import de.robv.android.xposed.callbacks.XC_InitPackageResources; import de.robv.android.xposed.callbacks.XC_InitPackageResources;
import de.robv.android.xposed.callbacks.XC_InitZygote;
import de.robv.android.xposed.callbacks.XC_LoadPackage;
import de.robv.android.xposed.callbacks.XCallback; import de.robv.android.xposed.callbacks.XCallback;
import de.robv.android.xposed.services.BaseService; import de.robv.android.xposed.services.BaseService;
import static de.robv.android.xposed.XposedBridge.clearAllCallbacks;
import static de.robv.android.xposed.XposedBridge.hookAllConstructors; import static de.robv.android.xposed.XposedBridge.hookAllConstructors;
import static de.robv.android.xposed.XposedBridge.hookAllMethods; import static de.robv.android.xposed.XposedBridge.hookAllMethods;
import static de.robv.android.xposed.XposedBridge.sInitPackageResourcesCallbacks;
import static de.robv.android.xposed.XposedBridge.sInitZygoteCallbacks;
import static de.robv.android.xposed.XposedBridge.sLoadedPackageCallbacks;
import static de.robv.android.xposed.XposedHelpers.callMethod; import static de.robv.android.xposed.XposedHelpers.callMethod;
import static de.robv.android.xposed.XposedHelpers.closeSilently; import static de.robv.android.xposed.XposedHelpers.closeSilently;
import static de.robv.android.xposed.XposedHelpers.findAndHookMethod; import static de.robv.android.xposed.XposedHelpers.findAndHookMethod;
@ -292,44 +300,104 @@ public final class XposedInit {
/** /**
* Try to load all modules defined in <code>INSTALLER_DATA_BASE_DIR/conf/modules.list</code> * Try to load all modules defined in <code>INSTALLER_DATA_BASE_DIR/conf/modules.list</code>
*/ */
private static volatile AtomicBoolean modulesLoaded = new AtomicBoolean(false); private static final AtomicBoolean modulesLoaded = new AtomicBoolean(false);
private static final Object moduleLoadLock = new Object();
// @GuardedBy("moduleLoadLock")
private static final ArraySet<String> loadedModules = new ArraySet<>();
// @GuardedBy("moduleLoadLock")
private static long lastModuleListModifiedTime = -1;
public static void loadModules(boolean isInZygote) throws IOException { public static boolean loadModules(boolean isInZygote, boolean callInitZygote) throws IOException {
boolean hasLoaded = !modulesLoaded.compareAndSet(false, true); boolean hasLoaded = !modulesLoaded.compareAndSet(false, true);
// dynamic module list mode doesn't apply to loading in zygote // dynamic module list mode doesn't apply to loading in zygote
if (hasLoaded && (isInZygote || !EdXpConfigGlobal.getConfig().isDynamicModulesMode())) { if (hasLoaded && (isInZygote || !EdXpConfigGlobal.getConfig().isDynamicModulesMode())) {
return; return false;
}
// FIXME module list is cleared but never could be reload again when using dynamic-module-list under multi-user environment
XposedBridge.clearLoadedPackages();
final String filename = EdXpConfigGlobal.getConfig().getInstallerBaseDir() + "conf/modules.list";
BaseService service = SELinuxHelper.getAppDataFileService();
if (!service.checkFileExists(filename)) {
Log.e(TAG, "Cannot load any modules because " + filename + " was not found");
return;
} }
synchronized (moduleLoadLock) {
final String filename = EdXpConfigGlobal.getConfig().getInstallerBaseDir() + "conf/modules.list";
BaseService service = SELinuxHelper.getAppDataFileService();
if (!service.checkFileExists(filename)) {
Log.e(TAG, "Cannot load any modules because " + filename + " was not found");
// FIXME module list is cleared but never could be reload again
// when using dynamic-module-list under multi-user environment
clearAllCallbacks();
return false;
}
ClassLoader topClassLoader = XposedBridge.BOOTCLASSLOADER; long moduleListModifiedTime = service.getFileModificationTime(filename);
ClassLoader parent; if (lastModuleListModifiedTime == moduleListModifiedTime) {
while ((parent = topClassLoader.getParent()) != null) { // module list has not changed
topClassLoader = parent; return false;
} }
ClassLoader topClassLoader = XposedBridge.BOOTCLASSLOADER;
ClassLoader parent;
while ((parent = topClassLoader.getParent()) != null) {
topClassLoader = parent;
}
InputStream stream = service.getFileInputStream(filename);
BufferedReader apks = new BufferedReader(new InputStreamReader(stream));
ArraySet<String> newLoadedApk = new ArraySet<>();
String apk;
while ((apk = apks.readLine()) != null) {
if (loadedModules.contains(apk)) {
newLoadedApk.add(apk);
} else {
boolean loadSuccess = loadModule(apk, topClassLoader, callInitZygote);
if (loadSuccess) {
newLoadedApk.add(apk);
}
}
}
loadedModules.clear();
loadedModules.addAll(newLoadedApk);
apks.close();
// refresh callback according to current loaded module list
pruneCallbacks(loadedModules);
lastModuleListModifiedTime = moduleListModifiedTime;
InputStream stream = service.getFileInputStream(filename);
BufferedReader apks = new BufferedReader(new InputStreamReader(stream));
String apk;
while ((apk = apks.readLine()) != null) {
loadModule(apk, topClassLoader);
} }
apks.close(); return true;
} }
// remove deactivated or outdated module callbacks
private static void pruneCallbacks(Set<String> loadedModules) {
synchronized (moduleLoadLock) {
Object[] loadedPkgSnapshot = sLoadedPackageCallbacks.getSnapshot();
Object[] initPkgResSnapshot = sInitPackageResourcesCallbacks.getSnapshot();
Object[] initZygoteSnapshot = sInitZygoteCallbacks.getSnapshot();
for (Object loadedPkg : loadedPkgSnapshot) {
if (loadedPkg instanceof IModuleContext) {
if (!loadedModules.contains(((IModuleContext) loadedPkg).getApkPath())) {
sLoadedPackageCallbacks.remove((XC_LoadPackage) loadedPkg);
}
}
}
for (Object initPkgRes : initPkgResSnapshot) {
if (initPkgRes instanceof IModuleContext) {
if (!loadedModules.contains(((IModuleContext) initPkgRes).getApkPath())) {
sInitPackageResourcesCallbacks.remove((XC_InitPackageResources) initPkgRes);
}
}
}
for (Object initZygote : initZygoteSnapshot) {
if (initZygote instanceof IModuleContext) {
if (!loadedModules.contains(((IModuleContext) initZygote).getApkPath())) {
sInitZygoteCallbacks.remove((XC_InitZygote) initZygote);
}
}
}
}
}
/** /**
* Load a module from an APK by calling the init(String) method for all classes defined * Load a module from an APK by calling the init(String) method for all classes defined
* in <code>assets/xposed_init</code>. * in <code>assets/xposed_init</code>.
*/ */
private static void loadModule(String apk, ClassLoader topClassLoader) { private static boolean loadModule(String apk, ClassLoader topClassLoader, boolean callInitZygote) {
Log.i(TAG, "Loading modules from " + apk); Log.i(TAG, "Loading modules from " + apk);
// todo remove this legacy logic // todo remove this legacy logic
@ -337,12 +405,12 @@ public final class XposedInit {
if (!TextUtils.isEmpty(apk) && !TextUtils.isEmpty(blackListModulePackageName) if (!TextUtils.isEmpty(apk) && !TextUtils.isEmpty(blackListModulePackageName)
&& apk.contains(blackListModulePackageName)) { && apk.contains(blackListModulePackageName)) {
Log.i(TAG, "We are going to take over black list's job..."); Log.i(TAG, "We are going to take over black list's job...");
return; return false;
} }
if (!new File(apk).exists()) { if (!new File(apk).exists()) {
Log.e(TAG, " File does not exist"); Log.e(TAG, " File does not exist");
return; return false;
} }
DexFile dexFile; DexFile dexFile;
@ -350,13 +418,13 @@ public final class XposedInit {
dexFile = new DexFile(apk); dexFile = new DexFile(apk);
} catch (IOException e) { } catch (IOException e) {
Log.e(TAG, " Cannot load module", e); Log.e(TAG, " Cannot load module", e);
return; return false;
} }
if (dexFile.loadClass(INSTANT_RUN_CLASS, topClassLoader) != null) { if (dexFile.loadClass(INSTANT_RUN_CLASS, topClassLoader) != null) {
Log.e(TAG, " Cannot load module, please disable \"Instant Run\" in Android Studio."); Log.e(TAG, " Cannot load module, please disable \"Instant Run\" in Android Studio.");
closeSilently(dexFile); closeSilently(dexFile);
return; return false;
} }
if (dexFile.loadClass(XposedBridge.class.getName(), topClassLoader) != null) { if (dexFile.loadClass(XposedBridge.class.getName(), topClassLoader) != null) {
@ -365,7 +433,7 @@ public final class XposedInit {
Log.e(TAG, " This may cause strange issues and must be fixed by the module developer."); Log.e(TAG, " This may cause strange issues and must be fixed by the module developer.");
Log.e(TAG, " For details, see: http://api.xposed.info/using.html"); Log.e(TAG, " For details, see: http://api.xposed.info/using.html");
closeSilently(dexFile); closeSilently(dexFile);
return; return false;
} }
closeSilently(dexFile); closeSilently(dexFile);
@ -378,13 +446,13 @@ public final class XposedInit {
if (zipEntry == null) { if (zipEntry == null) {
Log.e(TAG, " assets/xposed_init not found in the APK"); Log.e(TAG, " assets/xposed_init not found in the APK");
closeSilently(zipFile); closeSilently(zipFile);
return; return false;
} }
is = zipFile.getInputStream(zipEntry); is = zipFile.getInputStream(zipEntry);
} catch (IOException e) { } catch (IOException e) {
Log.e(TAG, " Cannot read assets/xposed_init in the APK", e); Log.e(TAG, " Cannot read assets/xposed_init in the APK", e);
closeSilently(zipFile); closeSilently(zipFile);
return; return false;
} }
ClassLoader mcl = new PathClassLoader(apk, XposedInit.class.getClassLoader()); ClassLoader mcl = new PathClassLoader(apk, XposedInit.class.getClassLoader());
@ -414,24 +482,21 @@ public final class XposedInit {
IXposedHookZygoteInit.StartupParam param = new IXposedHookZygoteInit.StartupParam(); IXposedHookZygoteInit.StartupParam param = new IXposedHookZygoteInit.StartupParam();
param.modulePath = apk; param.modulePath = apk;
param.startsSystemServer = startsSystemServer; param.startsSystemServer = startsSystemServer;
if (EdXpConfigGlobal.getConfig().isBlackWhiteListMode()
&& !EdXpConfigGlobal.getConfig().isDynamicModulesMode()) { XposedBridge.hookInitZygote(new IXposedHookZygoteInit.Wrapper(
// postpone initZygote callbacks under black/white list mode (IXposedHookZygoteInit) moduleInstance, param));
// if dynamic modules mode is on, callback directly cause we if (callInitZygote) {
// are already in app process here
XposedBridge.hookInitZygote(new IXposedHookZygoteInit.Wrapper(
(IXposedHookZygoteInit) moduleInstance, param));
} else {
// FIXME under dynamic modules mode, initZygote is called twice
((IXposedHookZygoteInit) moduleInstance).initZygote(param); ((IXposedHookZygoteInit) moduleInstance).initZygote(param);
} }
} }
if (moduleInstance instanceof IXposedHookLoadPackage) if (moduleInstance instanceof IXposedHookLoadPackage)
XposedBridge.hookLoadPackage(new IXposedHookLoadPackage.Wrapper((IXposedHookLoadPackage) moduleInstance)); XposedBridge.hookLoadPackage(new IXposedHookLoadPackage.Wrapper(
(IXposedHookLoadPackage) moduleInstance, apk));
if (moduleInstance instanceof IXposedHookInitPackageResources) if (moduleInstance instanceof IXposedHookInitPackageResources)
XposedBridge.hookInitPackageResources(new IXposedHookInitPackageResources.Wrapper((IXposedHookInitPackageResources) moduleInstance)); XposedBridge.hookInitPackageResources(new IXposedHookInitPackageResources.Wrapper(
(IXposedHookInitPackageResources) moduleInstance, apk));
} else { } else {
if (moduleInstance instanceof IXposedHookCmdInit) { if (moduleInstance instanceof IXposedHookCmdInit) {
IXposedHookCmdInit.StartupParam param = new IXposedHookCmdInit.StartupParam(); IXposedHookCmdInit.StartupParam param = new IXposedHookCmdInit.StartupParam();
@ -442,10 +507,13 @@ public final class XposedInit {
} }
} catch (Throwable t) { } catch (Throwable t) {
Log.e(TAG, " Failed to load class " + moduleClassName, t); Log.e(TAG, " Failed to load class " + moduleClassName, t);
return false;
} }
} }
return true;
} catch (IOException e) { } catch (IOException e) {
Log.e(TAG, " Failed to load module from " + apk, e); Log.e(TAG, " Failed to load module from " + apk, e);
return false;
} finally { } finally {
closeSilently(is); closeSilently(is);
closeSilently(zipFile); closeSilently(zipFile);

View File

@ -6,6 +6,7 @@ import com.elderdrivers.riru.edxp.config.EdXpConfigGlobal;
import java.io.Serializable; import java.io.Serializable;
import de.robv.android.xposed.IModuleContext;
import de.robv.android.xposed.XposedBridge; import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedBridge.CopyOnWriteSortedSet; import de.robv.android.xposed.XposedBridge.CopyOnWriteSortedSet;
@ -15,7 +16,7 @@ import de.robv.android.xposed.XposedBridge.CopyOnWriteSortedSet;
* This class only keeps a priority for ordering multiple callbacks. * This class only keeps a priority for ordering multiple callbacks.
* The actual (abstract) callback methods are added by subclasses. * The actual (abstract) callback methods are added by subclasses.
*/ */
public abstract class XCallback implements Comparable<XCallback> { public abstract class XCallback implements Comparable<XCallback>, IModuleContext {
/** /**
* Callback priority, higher number means earlier execution. * Callback priority, higher number means earlier execution.
* *
@ -121,6 +122,11 @@ public abstract class XCallback implements Comparable<XCallback> {
/** @hide */ /** @hide */
protected void call(Param param) throws Throwable {} protected void call(Param param) throws Throwable {}
@Override
public String getApkPath() {
return "";
}
/** @hide */ /** @hide */
@Override @Override
public int compareTo(XCallback other) { public int compareTo(XCallback other) {