Refactor dynamic modules feature
This commit is contained in:
parent
aed3318ee3
commit
2b6a39bd1a
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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)) {
|
||||||
|
|
|
||||||
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue