Fix potential bootloop on OnePlus devices when using black/white list mode
This commit is contained in:
parent
ff595542c4
commit
bb4fcffe20
|
|
@ -116,6 +116,8 @@ public class Main implements KeepAll {
|
|||
|
||||
public static native boolean isDynamicModulesEnabled();
|
||||
|
||||
public static native boolean isAppNeedHook(String appDataDir);
|
||||
|
||||
// prevent from fatal error caused by holding not whitelisted file descriptors when forking zygote
|
||||
// https://github.com/rovo89/Xposed/commit/b3ba245ad04cd485699fb1d2ebde7117e58214ff
|
||||
public static native void closeFilesBeforeForkNative();
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import com.elderdrivers.riru.xposed.dexmaker.DynamicBridge;
|
|||
import com.elderdrivers.riru.xposed.entry.bootstrap.AppBootstrapHookInfo;
|
||||
import com.elderdrivers.riru.xposed.entry.bootstrap.SysBootstrapHookInfo;
|
||||
import com.elderdrivers.riru.xposed.entry.bootstrap.SysInnerHookInfo;
|
||||
import com.elderdrivers.riru.xposed.entry.bootstrap.WorkAroundHookInfo;
|
||||
import com.elderdrivers.riru.xposed.entry.hooker.SystemMainHooker;
|
||||
import com.elderdrivers.riru.xposed.util.Utils;
|
||||
|
||||
|
|
@ -81,6 +82,13 @@ public class Router {
|
|||
SysInnerHookInfo.class.getName());
|
||||
}
|
||||
|
||||
public static void startWorkAroundHook() {
|
||||
HookMain.doHookDefault(
|
||||
Router.class.getClassLoader(),
|
||||
XposedBridge.BOOTCLASSLOADER,
|
||||
WorkAroundHookInfo.class.getName());
|
||||
}
|
||||
|
||||
public static void onEnterChildProcess() {
|
||||
forkCompleted = true;
|
||||
DynamicBridge.onForkPost();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
package com.elderdrivers.riru.xposed.entry.bootstrap;
|
||||
|
||||
import com.elderdrivers.riru.common.KeepMembers;
|
||||
import com.elderdrivers.riru.xposed.entry.hooker.OnePlusWorkAroundHooker;
|
||||
|
||||
public class WorkAroundHookInfo implements KeepMembers {
|
||||
public static String[] hookItemNames = {
|
||||
OnePlusWorkAroundHooker.class.getName()
|
||||
};
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ import com.elderdrivers.riru.xposed.config.ConfigManager;
|
|||
import com.elderdrivers.riru.xposed.entry.Router;
|
||||
import com.elderdrivers.riru.xposed.util.PrebuiltMethodsDeopter;
|
||||
|
||||
import static com.elderdrivers.riru.xposed.Main.isAppNeedHook;
|
||||
import static com.elderdrivers.riru.xposed.util.FileUtils.getDataPathPrefix;
|
||||
|
||||
public class BlackWhiteListProxy {
|
||||
|
|
@ -14,63 +15,77 @@ public class BlackWhiteListProxy {
|
|||
String niceName, int[] fdsToClose, int[] fdsToIgnore,
|
||||
boolean startChildZygote, String instructionSet,
|
||||
String appDataDir) {
|
||||
// always enter here, make sure secondary zygote's modules is loaded only once
|
||||
// when isDynamicModulesMode is not on
|
||||
final boolean isDynamicModulesMode = Main.isDynamicModulesEnabled();
|
||||
ConfigManager.setDynamicModulesMode(isDynamicModulesMode);
|
||||
// call this to ensure the flag is set to false ASAP
|
||||
Router.prepare(false);
|
||||
PrebuiltMethodsDeopter.deoptBootMethods(); // do it once for secondary zygote
|
||||
if (!isDynamicModulesMode) {
|
||||
Router.loadModulesSafely();
|
||||
Main.closeFilesBeforeForkNative();
|
||||
if (isDynamicModulesMode) {
|
||||
// should never happen
|
||||
return;
|
||||
}
|
||||
// only enter here when isDynamicModulesMode is off
|
||||
onForkPreForNonDynamicMode(false);
|
||||
}
|
||||
|
||||
public static void forkAndSpecializePost(int pid, String appDataDir) {
|
||||
// when this process is in white list or not in black list
|
||||
// installBootstrapHooks -> loadModules if needed
|
||||
final boolean isDynamicModulesMode = Main.isDynamicModulesEnabled();
|
||||
if (!isDynamicModulesMode) {
|
||||
Main.reopenFilesAfterForkNative();
|
||||
}
|
||||
Main.appDataDir = appDataDir;
|
||||
ConfigManager.setDynamicModulesMode(isDynamicModulesMode);
|
||||
Router.onEnterChildProcess();
|
||||
Router.installBootstrapHooks(false);
|
||||
Router.loadModulesSafely();
|
||||
onForkPostCommon(false, appDataDir);
|
||||
}
|
||||
|
||||
public static void forkSystemServerPre(int uid, int gid, int[] gids, int debugFlags,
|
||||
int[][] rlimits, long permittedCapabilities,
|
||||
long effectiveCapabilities) {
|
||||
// we always enter here whether black/white list is on or not
|
||||
final boolean isDynamicModulesMode = Main.isDynamicModulesEnabled();
|
||||
ConfigManager.setDynamicModulesMode(isDynamicModulesMode);
|
||||
PrebuiltMethodsDeopter.deoptBootMethods(); // do it once for main zygote
|
||||
// set startsSystemServer flag used when loadModules
|
||||
Router.prepare(true);
|
||||
// we never install bootstrap hooks here in black/white list mode
|
||||
// because installed hooks would be propagated to all child processes of main zygote
|
||||
// hence we cannot install hooks for processes like com.android.phone process who are
|
||||
// not from forkAndSpecialize as a side effect
|
||||
if (!isDynamicModulesMode) {
|
||||
Router.loadModulesSafely();
|
||||
Main.closeFilesBeforeForkNative();
|
||||
if (isDynamicModulesMode) {
|
||||
// should never happen
|
||||
return;
|
||||
}
|
||||
// only enter here when isDynamicModulesMode is off
|
||||
onForkPreForNonDynamicMode(true);
|
||||
}
|
||||
|
||||
public static void forkSystemServerPost(int pid) {
|
||||
// should only here when system_server is in white list or not in black list
|
||||
// installBootstrapHooks -> loadModules if needed
|
||||
onForkPostCommon(true, getDataPathPrefix() + "android");
|
||||
}
|
||||
|
||||
/**
|
||||
* Some details are different between main zygote and secondary zygote.
|
||||
*/
|
||||
private static void onForkPreForNonDynamicMode(boolean isSystemServer) {
|
||||
ConfigManager.setDynamicModulesMode(false);
|
||||
// deoptBootMethods once for all child processes of zygote
|
||||
PrebuiltMethodsDeopter.deoptBootMethods();
|
||||
// set startsSystemServer flag used when loadModules
|
||||
Router.prepare(isSystemServer);
|
||||
// we never install bootstrap hooks here in black/white list mode except workaround hooks
|
||||
// because installed hooks would be propagated to all child processes of zygote
|
||||
Router.startWorkAroundHook();
|
||||
// loadModules once for all child processes of zygote
|
||||
Router.loadModulesSafely();
|
||||
// at last close all fds
|
||||
Main.closeFilesBeforeForkNative();
|
||||
}
|
||||
|
||||
private static void onForkPostCommon(boolean isSystemServer, String appDataDir) {
|
||||
final boolean isDynamicModulesMode = Main.isDynamicModulesEnabled();
|
||||
// set common flags
|
||||
ConfigManager.setDynamicModulesMode(isDynamicModulesMode);
|
||||
Main.appDataDir = appDataDir;
|
||||
Router.onEnterChildProcess();
|
||||
|
||||
if (!isDynamicModulesMode) {
|
||||
// initial stuffs have been done in forkSystemServerPre
|
||||
Main.reopenFilesAfterForkNative();
|
||||
}
|
||||
Main.appDataDir = getDataPathPrefix() + "android";
|
||||
ConfigManager.setDynamicModulesMode(isDynamicModulesMode);
|
||||
Router.onEnterChildProcess();
|
||||
Router.installBootstrapHooks(true);
|
||||
Router.loadModulesSafely();
|
||||
|
||||
if (!isAppNeedHook(Main.appDataDir)) {
|
||||
// if is blacklisted, just stop here
|
||||
return;
|
||||
}
|
||||
|
||||
if (isDynamicModulesMode) {
|
||||
// nothing has been done in forkSystemServerPre, we have to do the same here
|
||||
// except some workarounds specific for forkSystemServerPre
|
||||
PrebuiltMethodsDeopter.deoptBootMethods();
|
||||
Router.prepare(isSystemServer);
|
||||
Router.loadModulesSafely();
|
||||
}
|
||||
Router.installBootstrapHooks(isSystemServer);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ public class PrebuiltMethodsDeopter {
|
|||
}
|
||||
|
||||
public static void deoptBootMethods() {
|
||||
// todo check if has been done before
|
||||
deoptMethods(KEY_BOOT_IMAGE, null);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ static void init_once() {
|
|||
|
||||
static char package_name[256];
|
||||
|
||||
bool is_app_need_hook(JNIEnv *env, jstring appDataDir) {
|
||||
bool is_app_need_hook(JNIEnv *env, jclass, jstring appDataDir) {
|
||||
init_once();
|
||||
if (!black_white_list_enabled) {
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
#include <jni.h>
|
||||
|
||||
bool is_app_need_hook(JNIEnv *env, jstring appDataDir);
|
||||
bool is_app_need_hook(JNIEnv *env, jclass, jstring appDataDir);
|
||||
|
||||
bool is_black_white_list_enabled();
|
||||
|
||||
|
|
|
|||
|
|
@ -57,9 +57,6 @@ void onNativeForkSystemServerPre(JNIEnv *env, jclass clazz, uid_t uid, gid_t gid
|
|||
|
||||
int onNativeForkSystemServerPost(JNIEnv *env, jclass clazz, jint res) {
|
||||
if (res == 0) {
|
||||
if (!is_app_need_hook(env, sAppDataDir)) {
|
||||
return 0;
|
||||
}
|
||||
prepareJavaEnv(env);
|
||||
// only do work in child since findAndCall would print log
|
||||
findAndCall(env, "forkSystemServerPost", "(I)V", res);
|
||||
|
|
@ -100,9 +97,6 @@ void onNativeForkAndSpecializePre(JNIEnv *env, jclass clazz,
|
|||
|
||||
int onNativeForkAndSpecializePost(JNIEnv *env, jclass clazz, jint res) {
|
||||
if (res == 0) {
|
||||
if (!is_app_need_hook(env, sAppDataDir)) {
|
||||
return 0;
|
||||
}
|
||||
prepareJavaEnv(env);
|
||||
findAndCall(env, "forkAndSpecializePost", "(ILjava/lang/String;)V", res, sAppDataDir);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -79,6 +79,9 @@ static JNINativeMethod hookMethods[] = {
|
|||
{
|
||||
"isDynamicModulesEnabled", "()Z", (void *) is_dynamic_modules_enabled
|
||||
},
|
||||
{
|
||||
"isAppNeedHook", "(Ljava/lang/String;)Z", (void *) is_app_need_hook
|
||||
},
|
||||
{
|
||||
"getInstallerPkgName", "()Ljava/lang/String;", (void *) get_installer_pkg_name
|
||||
},
|
||||
|
|
@ -134,7 +137,7 @@ void loadDexAndInit(JNIEnv *env, const char *dexPath) {
|
|||
jclass entry_class = findClassFromLoader(env, myClassLoader, ENTRY_CLASS_NAME);
|
||||
if (NULL != entry_class) {
|
||||
LOGD("HookEntry Class %p", entry_class);
|
||||
env->RegisterNatives(entry_class, hookMethods, 12);
|
||||
env->RegisterNatives(entry_class, hookMethods, 13);
|
||||
isInited = true;
|
||||
LOGD("RegisterNatives succeed for HookEntry.");
|
||||
} else {
|
||||
|
|
|
|||
Loading…
Reference in New Issue