Refactor dynamic modules feature

This commit is contained in:
solohsu 2019-02-20 15:00:19 +08:00
parent aed3318ee3
commit 2b6a39bd1a
8 changed files with 49 additions and 34 deletions

View File

@ -18,17 +18,17 @@ import static com.elderdrivers.riru.xposed.util.FileUtils.getDataPathPrefix;
@SuppressLint("DefaultLocale") @SuppressLint("DefaultLocale")
public class Main implements KeepAll { public class Main implements KeepAll {
public static String sAppDataDir = ""; public static String appDataDir = "";
public static String sAppProcessName = ""; public static String appProcessName = "";
private static String sForkAndSpecializePramsStr = "";
private static String sForkSystemServerPramsStr = "";
/** /**
* When set to true, install bootstrap hooks and loadModules * When set to true, install bootstrap hooks and loadModules
* for each process when it starts. * for each process when it starts.
* This means you can deactivate or activate every module * This means you can deactivate or activate every module
* for the process you restart without rebooting. * for the process you restart without rebooting.
*/ */
private static boolean sIsDynamicModules = false; public static boolean isDynamicModules = false;
private static String forkAndSpecializePramsStr = "";
private static String forkSystemServerPramsStr = "";
static { static {
init(Build.VERSION.SDK_INT); init(Build.VERSION.SDK_INT);
@ -45,29 +45,27 @@ public class Main implements KeepAll {
boolean startChildZygote, String instructionSet, boolean startChildZygote, String instructionSet,
String appDataDir, boolean isDynamicModules) { String appDataDir, boolean isDynamicModules) {
if (BuildConfig.DEBUG) { if (BuildConfig.DEBUG) {
sForkAndSpecializePramsStr = String.format( forkAndSpecializePramsStr = String.format(
"Zygote#forkAndSpecialize(%d, %d, %s, %d, %s, %d, %s, %s, %s, %s, %s, %s, %s)", "Zygote#forkAndSpecialize(%d, %d, %s, %d, %s, %d, %s, %s, %s, %s, %s, %s, %s)",
uid, gid, Arrays.toString(gids), debugFlags, Arrays.toString(rlimits), uid, gid, Arrays.toString(gids), debugFlags, Arrays.toString(rlimits),
mountExternal, seInfo, niceName, Arrays.toString(fdsToClose), mountExternal, seInfo, niceName, Arrays.toString(fdsToClose),
Arrays.toString(fdsToIgnore), startChildZygote, instructionSet, appDataDir); Arrays.toString(fdsToIgnore), startChildZygote, instructionSet, appDataDir);
} }
sAppDataDir = appDataDir; Main.appDataDir = appDataDir;
sIsDynamicModules = isDynamicModules; Main.isDynamicModules = isDynamicModules;
Router.prepare(false); Router.prepare(false);
// install bootstrap hooks for secondary zygote // install bootstrap hooks for secondary zygote
Router.installBootstrapHooks(false); Router.installBootstrapHooks(false);
if (!isDynamicModules) { // load modules for secondary zygote
// load modules only once in zygote process Router.loadModulesSafely();
Router.loadModulesSafely();
}
} }
public static void forkAndSpecializePost(int pid, String appDataDir) { public static void forkAndSpecializePost(int pid, String appDataDir) {
if (pid == 0) { if (pid == 0) {
Utils.logD(sForkAndSpecializePramsStr + " = " + Process.myPid()); Utils.logD(forkAndSpecializePramsStr + " = " + Process.myPid());
Router.onEnterChildProcess(); Router.onEnterChildProcess();
DynamicBridge.onForkPost(); DynamicBridge.onForkPost();
if (sIsDynamicModules) { if (isDynamicModules) {
// load modules for each app process on its forked // load modules for each app process on its forked
Router.loadModulesSafely(); Router.loadModulesSafely();
} }
@ -78,26 +76,31 @@ public class Main implements KeepAll {
} }
public static void forkSystemServerPre(int uid, int gid, int[] gids, int debugFlags, int[][] rlimits, public static void forkSystemServerPre(int uid, int gid, int[] gids, int debugFlags, int[][] rlimits,
long permittedCapabilities, long effectiveCapabilities) { long permittedCapabilities, long effectiveCapabilities,
boolean isDynamicModules) {
if (BuildConfig.DEBUG) { if (BuildConfig.DEBUG) {
sForkSystemServerPramsStr = String.format("Zygote#forkSystemServer(%d, %d, %s, %d, %s, %d, %d)", forkSystemServerPramsStr = String.format("Zygote#forkSystemServer(%d, %d, %s, %d, %s, %d, %d)",
uid, gid, Arrays.toString(gids), debugFlags, Arrays.toString(rlimits), uid, gid, Arrays.toString(gids), debugFlags, Arrays.toString(rlimits),
permittedCapabilities, effectiveCapabilities); permittedCapabilities, effectiveCapabilities);
} }
sAppDataDir = getDataPathPrefix() + "android"; Main.appDataDir = getDataPathPrefix() + "android";
sIsDynamicModules = false; Main.isDynamicModules = isDynamicModules;
Router.prepare(true);
// install bootstrap hooks for main zygote as early as possible // install bootstrap hooks for main zygote as early as possible
// in case we miss some processes // in case we miss some processes not forked via forkAndSpecialize
// for instance com.android.phone
Router.installBootstrapHooks(true); Router.installBootstrapHooks(true);
// loadModules have to be executed in zygote even isDynamicModules is false
// because if not global hooks installed in initZygote might not be
// propagated to processes not forked via forkAndSpecialize
Router.loadModulesSafely();
} }
public static void forkSystemServerPost(int pid) { public static void forkSystemServerPost(int pid) {
if (pid == 0) { if (pid == 0) {
Utils.logD(sForkSystemServerPramsStr + " = " + Process.myPid()); Utils.logD(forkSystemServerPramsStr + " = " + Process.myPid());
// in system_server process // in system_server process
Router.onEnterChildProcess(); Router.onEnterChildProcess();
Router.prepare(true);
Router.loadModulesSafely();
} else { } else {
// in zygote process, res is child zygote pid // in zygote process, res is child zygote pid
// don't print log here, see https://github.com/RikkaApps/Riru/blob/77adfd6a4a6a81bfd20569c910bc4854f2f84f5e/riru-core/jni/main/jni_native_method.cpp#L55-L66 // don't print log here, see https://github.com/RikkaApps/Riru/blob/77adfd6a4a6a81bfd20569c910bc4854f2f84f5e/riru-core/jni/main/jni_native_method.cpp#L55-L66

View File

@ -25,8 +25,8 @@ public class DexMakerUtils {
} }
String packageName = AndroidAppHelper.currentPackageName(); String packageName = AndroidAppHelper.currentPackageName();
if (TextUtils.isEmpty(packageName)) { //default to true if (TextUtils.isEmpty(packageName)) { //default to true
DexLog.w("packageName is empty, processName=" + Main.sAppProcessName DexLog.w("packageName is empty, processName=" + Main.appProcessName
+ ", appDataDir=" + Main.sAppDataDir); + ", appDataDir=" + Main.appDataDir);
return true; return true;
} }
return !SELinuxHelper.getAppDataFileService().checkFileExists(COMPAT_LIST_PATH + packageName); return !SELinuxHelper.getAppDataFileService().checkFileExists(COMPAT_LIST_PATH + packageName);

View File

@ -53,12 +53,12 @@ public final class DynamicBridge {
try { try {
// we always choose to use device encrypted storage data on android N and later // we always choose to use device encrypted storage data on android N and later
// in case some app is installing hooks before phone is unlocked // in case some app is installing hooks before phone is unlocked
String fixedAppDataDir = getDataPathPrefix() + getPackageName(Main.sAppDataDir) + "/"; String fixedAppDataDir = getDataPathPrefix() + getPackageName(Main.appDataDir) + "/";
dexDir = new File(fixedAppDataDir, "/cache/edhookers/" dexDir = new File(fixedAppDataDir, "/cache/edhookers/"
+ getCurrentProcessName().replace(":", "_") + "/"); + getCurrentProcessName().replace(":", "_") + "/");
dexOptDir = new File(dexDir, "oat"); dexOptDir = new File(dexDir, "oat");
dexDir.mkdirs(); dexDir.mkdirs();
DexLog.d(Main.sAppProcessName + " deleting dir: " + dexOptDir.getAbsolutePath()); DexLog.d(Main.appProcessName + " deleting dir: " + dexOptDir.getAbsolutePath());
try { try {
FileUtils.delete(dexOptDir); FileUtils.delete(dexOptDir);
} catch (Throwable throwable) { } catch (Throwable throwable) {

View File

@ -39,10 +39,10 @@ public class HandleBindAppHooker implements KeepMembers {
ActivityThread activityThread = (ActivityThread) thiz; ActivityThread activityThread = (ActivityThread) thiz;
ApplicationInfo appInfo = (ApplicationInfo) getObjectField(bindData, "appInfo"); ApplicationInfo appInfo = (ApplicationInfo) getObjectField(bindData, "appInfo");
// save app process name here for later use // save app process name here for later use
Main.sAppProcessName = (String) getObjectField(bindData, "processName"); Main.appProcessName = (String) getObjectField(bindData, "processName");
String reportedPackageName = appInfo.packageName.equals("android") ? "system" : appInfo.packageName; String reportedPackageName = appInfo.packageName.equals("android") ? "system" : appInfo.packageName;
Utils.logD("processName=" + Main.sAppProcessName + Utils.logD("processName=" + Main.appProcessName +
", packageName=" + reportedPackageName + ", appDataDir=" + Main.sAppDataDir); ", packageName=" + reportedPackageName + ", appDataDir=" + Main.appDataDir);
if (XposedBlackListHooker.shouldDisableHooks(reportedPackageName)) { if (XposedBlackListHooker.shouldDisableHooks(reportedPackageName)) {
return; return;

View File

@ -13,7 +13,7 @@ import java.io.InputStreamReader;
public class ProcessUtils { public class ProcessUtils {
public static String getCurrentProcessName() { public static String getCurrentProcessName() {
String prettyName = Main.sAppProcessName; String prettyName = Main.appProcessName;
if (!TextUtils.isEmpty(prettyName)) { if (!TextUtils.isEmpty(prettyName)) {
return prettyName; return prettyName;
} }
@ -23,7 +23,7 @@ public class ProcessUtils {
/** /**
* a common solution from https://stackoverflow.com/a/21389402 * a common solution from https://stackoverflow.com/a/21389402
* <p> * <p>
* use {@link com.elderdrivers.riru.xposed.Main#sAppProcessName} to get current process name * use {@link com.elderdrivers.riru.xposed.Main#appProcessName} to get current process name
*/ */
public static String getProcessName(int pid) { public static String getProcessName(int pid) {
BufferedReader cmdlineReader = null; BufferedReader cmdlineReader = null;

View File

@ -372,6 +372,12 @@ public final class XposedBridge {
} }
} }
public static void clearLoadedPackages() {
synchronized (sLoadedPackageCallbacks) {
sLoadedPackageCallbacks.clear();
}
}
/** /**
* Adds a callback to be executed when the resources for an app are initialized. * Adds a callback to be executed when the resources for an app are initialized.
* *
@ -526,6 +532,10 @@ public final class XposedBridge {
public Object[] getSnapshot() { public Object[] getSnapshot() {
return elements; return elements;
} }
public synchronized void clear() {
elements = EMPTY_ARRAY;
}
} }
public static class AdditionalHookInfo { public static class AdditionalHookInfo {

View File

@ -8,6 +8,7 @@ import android.util.Log;
import com.android.internal.os.ZygoteInit; import com.android.internal.os.ZygoteInit;
import com.elderdrivers.riru.xposed.BuildConfig; import com.elderdrivers.riru.xposed.BuildConfig;
import com.elderdrivers.riru.xposed.Main;
import com.elderdrivers.riru.xposed.entry.Router; import com.elderdrivers.riru.xposed.entry.Router;
import com.elderdrivers.riru.xposed.util.Utils; import com.elderdrivers.riru.xposed.util.Utils;
@ -93,9 +94,10 @@ public final class XposedInit {
private static volatile AtomicBoolean modulesLoaded = new AtomicBoolean(false); private static volatile AtomicBoolean modulesLoaded = new AtomicBoolean(false);
public static void loadModules() throws IOException { public static void loadModules() throws IOException {
if (!modulesLoaded.compareAndSet(false, true)) { if (!modulesLoaded.compareAndSet(false, true) && !Main.isDynamicModules) {
return; return;
} }
XposedBridge.clearLoadedPackages();
final String filename = INSTALLER_DATA_BASE_DIR + "conf/modules.list"; final String filename = INSTALLER_DATA_BASE_DIR + "conf/modules.list";
BaseService service = SELinuxHelper.getAppDataFileService(); BaseService service = SELinuxHelper.getAppDataFileService();
if (!service.checkFileExists(filename)) { if (!service.checkFileExists(filename)) {

View File

@ -47,8 +47,8 @@ void onNativeForkSystemServerPre(JNIEnv *env, jclass clazz, uid_t uid, gid_t gid
} }
prepareJavaEnv(env); prepareJavaEnv(env);
// jump to java code // jump to java code
findAndCall(env, "forkSystemServerPre", "(II[II[[IJJ)V", uid, gid, gids, runtime_flags, rlimits, findAndCall(env, "forkSystemServerPre", "(II[II[[IJJZ)V", uid, gid, gids, runtime_flags, rlimits,
permittedCapabilities, effectiveCapabilities); permittedCapabilities, effectiveCapabilities, is_dynamic_modules());
} }