Fix wrong dex path when using compat mode in some cases
This commit is contained in:
parent
285ced4cf9
commit
5a2cf52450
|
|
@ -5,6 +5,7 @@ import android.os.Build;
|
||||||
|
|
||||||
import com.elderdrivers.riru.common.KeepAll;
|
import com.elderdrivers.riru.common.KeepAll;
|
||||||
import com.elderdrivers.riru.xposed.core.HookMethodResolver;
|
import com.elderdrivers.riru.xposed.core.HookMethodResolver;
|
||||||
|
import com.elderdrivers.riru.xposed.dexmaker.DynamicBridge;
|
||||||
import com.elderdrivers.riru.xposed.entry.Router;
|
import com.elderdrivers.riru.xposed.entry.Router;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
|
@ -55,9 +56,11 @@ public class Main implements KeepAll {
|
||||||
sIsGlobalMode = isGlobalMode;
|
sIsGlobalMode = isGlobalMode;
|
||||||
sIsDynamicModules = isDynamicModules;
|
sIsDynamicModules = isDynamicModules;
|
||||||
if (isGlobalMode) {
|
if (isGlobalMode) {
|
||||||
|
// do bootstrap hooking only once in zygote process
|
||||||
Router.onProcessForked(false);
|
Router.onProcessForked(false);
|
||||||
}
|
}
|
||||||
if (!sIsDynamicModules) {
|
if (!isDynamicModules) {
|
||||||
|
// load modules only once in zygote process
|
||||||
Router.loadModulesSafely();
|
Router.loadModulesSafely();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -65,11 +68,14 @@ public class Main implements KeepAll {
|
||||||
public static void forkAndSpecializePost(int pid, String appDataDir) {
|
public static void forkAndSpecializePost(int pid, String appDataDir) {
|
||||||
// Utils.logD(sForkAndSpecializePramsStr + " = " + pid);
|
// Utils.logD(sForkAndSpecializePramsStr + " = " + pid);
|
||||||
if (pid == 0) {
|
if (pid == 0) {
|
||||||
|
DynamicBridge.onForkPost();
|
||||||
// in app process
|
// in app process
|
||||||
if (!sIsGlobalMode) {
|
if (!sIsGlobalMode) {
|
||||||
|
// do bootstrap hooking separately for each app process
|
||||||
Router.onProcessForked(false);
|
Router.onProcessForked(false);
|
||||||
}
|
}
|
||||||
if (sIsDynamicModules) {
|
if (sIsDynamicModules) {
|
||||||
|
// load modules for each app process on its forked
|
||||||
Router.loadModulesSafely();
|
Router.loadModulesSafely();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -83,7 +89,8 @@ public class Main implements KeepAll {
|
||||||
// sForkSystemServerPramsStr = String.format("Zygote#forkSystemServer(%d, %d, %s, %d, %s, %d, %d)",
|
// sForkSystemServerPramsStr = 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/";
|
sAppDataDir = getDataPathPrefix() + "android";
|
||||||
|
// system_server process doesn't need sIsGlobalMode and sIsDynamicModules
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void forkSystemServerPost(int pid) {
|
public static void forkSystemServerPost(int pid) {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
package com.elderdrivers.riru.xposed.dexmaker;
|
package com.elderdrivers.riru.xposed.dexmaker;
|
||||||
|
|
||||||
import android.app.AndroidAppHelper;
|
|
||||||
|
|
||||||
import com.elderdrivers.riru.xposed.Main;
|
import com.elderdrivers.riru.xposed.Main;
|
||||||
import com.elderdrivers.riru.xposed.util.FileUtils;
|
import com.elderdrivers.riru.xposed.util.FileUtils;
|
||||||
|
|
||||||
|
|
@ -18,22 +16,19 @@ import de.robv.android.xposed.XposedBridge;
|
||||||
|
|
||||||
import static com.elderdrivers.riru.xposed.dexmaker.DexMakerUtils.shouldUseInMemoryHook;
|
import static com.elderdrivers.riru.xposed.dexmaker.DexMakerUtils.shouldUseInMemoryHook;
|
||||||
import static com.elderdrivers.riru.xposed.util.FileUtils.getDataPathPrefix;
|
import static com.elderdrivers.riru.xposed.util.FileUtils.getDataPathPrefix;
|
||||||
|
import static com.elderdrivers.riru.xposed.util.FileUtils.getPackageName;
|
||||||
|
import static com.elderdrivers.riru.xposed.util.ProcessUtils.getCurrentProcessName;
|
||||||
|
|
||||||
public final class DynamicBridge {
|
public final class DynamicBridge {
|
||||||
|
|
||||||
private static final HashMap<Member, Method> hookedInfo = new HashMap<>();
|
private static final HashMap<Member, Method> hookedInfo = new HashMap<>();
|
||||||
private static final HookerDexMaker dexMaker = new HookerDexMaker();
|
private static final HookerDexMaker dexMaker = new HookerDexMaker();
|
||||||
private static final AtomicBoolean dexPathInited = new AtomicBoolean(false);
|
private static final AtomicBoolean dexPathInited = new AtomicBoolean(false);
|
||||||
private static final File dexDir;
|
private static File dexDir;
|
||||||
private static final File dexOptDir;
|
private static File dexOptDir;
|
||||||
|
|
||||||
static {
|
public static void onForkPost() {
|
||||||
// we always choose to use device encrypted storage data on android n and later
|
dexPathInited.set(false);
|
||||||
// in case some app is installing hooks before phone is unlocked
|
|
||||||
String fixedAppDataDir = getDataPathPrefix() + AndroidAppHelper.currentPackageName() + "/";
|
|
||||||
dexDir = new File(fixedAppDataDir, "/cache/edhookers/"
|
|
||||||
+ Main.sAppProcessName.replace(":", "_") + "/");
|
|
||||||
dexOptDir = new File(dexDir, "oat");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static synchronized void hookMethod(Member hookMethod, XposedBridge.AdditionalHookInfo additionalHookInfo) {
|
public static synchronized void hookMethod(Member hookMethod, XposedBridge.AdditionalHookInfo additionalHookInfo) {
|
||||||
|
|
@ -51,20 +46,30 @@ public final class DynamicBridge {
|
||||||
try {
|
try {
|
||||||
// for Android Oreo and later use InMemoryClassLoader
|
// for Android Oreo and later use InMemoryClassLoader
|
||||||
if (!shouldUseInMemoryHook()) {
|
if (!shouldUseInMemoryHook()) {
|
||||||
// under Android Oreo, using DexClassLoader
|
// using file based DexClassLoader
|
||||||
if (dexPathInited.compareAndSet(false, true)) {
|
if (dexPathInited.compareAndSet(false, true)) {
|
||||||
// delete previous compiled dex to prevent potential crashing
|
// delete previous compiled dex to prevent potential crashing
|
||||||
// TODO find a way to reuse them in consideration of performance
|
// TODO find a way to reuse them in consideration of performance
|
||||||
try {
|
try {
|
||||||
|
// 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
|
||||||
|
String fixedAppDataDir = getDataPathPrefix() + getPackageName(Main.sAppDataDir) + "/";
|
||||||
|
dexDir = new File(fixedAppDataDir, "/cache/edhookers/"
|
||||||
|
+ getCurrentProcessName().replace(":", "_") + "/");
|
||||||
|
dexOptDir = new File(dexDir, "oat");
|
||||||
dexDir.mkdirs();
|
dexDir.mkdirs();
|
||||||
DexLog.d(Main.sAppProcessName + " deleting dir: " + dexOptDir.getAbsolutePath());
|
DexLog.d(Main.sAppProcessName + " deleting dir: " + dexOptDir.getAbsolutePath());
|
||||||
FileUtils.delete(dexOptDir);
|
try {
|
||||||
|
FileUtils.delete(dexOptDir);
|
||||||
|
} catch (Throwable throwable) {
|
||||||
|
}
|
||||||
} catch (Throwable throwable) {
|
} catch (Throwable throwable) {
|
||||||
|
DexLog.e("error when init dex path", throwable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dexMaker.start(hookMethod, additionalHookInfo,
|
dexMaker.start(hookMethod, additionalHookInfo,
|
||||||
hookMethod.getDeclaringClass().getClassLoader(), dexDir.getAbsolutePath());
|
hookMethod.getDeclaringClass().getClassLoader(), dexDir == null ? null : dexDir.getAbsolutePath());
|
||||||
hookedInfo.put(hookMethod, dexMaker.getCallBackupMethod());
|
hookedInfo.put(hookMethod, dexMaker.getCallBackupMethod());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
DexLog.e("error occur when generating dex. dexDir=" + dexDir, e);
|
DexLog.e("error occur when generating dex. dexDir=" + dexDir, e);
|
||||||
|
|
|
||||||
|
|
@ -13,11 +13,11 @@ import de.robv.android.xposed.XposedInit;
|
||||||
public class Router {
|
public class Router {
|
||||||
|
|
||||||
public static void onProcessForked(boolean isSystem) {
|
public static void onProcessForked(boolean isSystem) {
|
||||||
// Initialize the Xposed framework and modules
|
// Initialize the Xposed framework
|
||||||
try {
|
try {
|
||||||
XposedInit.initForZygote(isSystem);
|
XposedInit.initForZygote(isSystem);
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
Utils.logE("Errors during Xposed initialization", t);
|
Utils.logE("error during Xposed initialization", t);
|
||||||
XposedBridge.disableHooks = true;
|
XposedBridge.disableHooks = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package com.elderdrivers.riru.xposed.util;
|
package com.elderdrivers.riru.xposed.util;
|
||||||
|
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.BufferedWriter;
|
import java.io.BufferedWriter;
|
||||||
|
|
@ -58,6 +59,18 @@ public class FileUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String getPackageName(String dataDir) {
|
||||||
|
if (TextUtils.isEmpty(dataDir)) {
|
||||||
|
Utils.logE("getPackageName using empty dataDir");
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
int lastIndex = dataDir.lastIndexOf("/");
|
||||||
|
if (lastIndex < 0) {
|
||||||
|
return dataDir;
|
||||||
|
}
|
||||||
|
return dataDir.substring(lastIndex + 1);
|
||||||
|
}
|
||||||
|
|
||||||
public static String getDataPathPrefix() {
|
public static String getDataPathPrefix() {
|
||||||
return IS_USING_PROTECTED_STORAGE ? "/data/user_de/0/" : "/data/data/";
|
return IS_USING_PROTECTED_STORAGE ? "/data/user_de/0/" : "/data/data/";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,10 @@
|
||||||
package com.elderdrivers.riru.xposed.util;
|
package com.elderdrivers.riru.xposed.util;
|
||||||
|
|
||||||
|
import android.os.Process;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
|
||||||
|
import com.elderdrivers.riru.xposed.Main;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
|
|
@ -7,6 +12,14 @@ import java.io.InputStreamReader;
|
||||||
|
|
||||||
public class ProcessUtils {
|
public class ProcessUtils {
|
||||||
|
|
||||||
|
public static String getCurrentProcessName() {
|
||||||
|
String prettyName = Main.sAppProcessName;
|
||||||
|
if (!TextUtils.isEmpty(prettyName)) {
|
||||||
|
return prettyName;
|
||||||
|
}
|
||||||
|
return getProcessName(Process.myPid());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* a common solution from https://stackoverflow.com/a/21389402
|
* a common solution from https://stackoverflow.com/a/21389402
|
||||||
* <p>
|
* <p>
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ public final class XposedInit {
|
||||||
public static final String INSTALLER_PACKAGE_NAME = "com.solohsu.android.edxp.manager";
|
public static final String INSTALLER_PACKAGE_NAME = "com.solohsu.android.edxp.manager";
|
||||||
public static final String INSTALLER_LEGACY_PACKAGE_NAME = "de.robv.android.xposed.installer";
|
public static final String INSTALLER_LEGACY_PACKAGE_NAME = "de.robv.android.xposed.installer";
|
||||||
@SuppressLint("SdCardPath")
|
@SuppressLint("SdCardPath")
|
||||||
private static final String BASE_DIR = Build.VERSION.SDK_INT >= 24
|
public static final String INSTALLER_DATA_BASE_DIR = Build.VERSION.SDK_INT >= 24
|
||||||
? "/data/user_de/0/" + INSTALLER_PACKAGE_NAME + "/"
|
? "/data/user_de/0/" + INSTALLER_PACKAGE_NAME + "/"
|
||||||
: "/data/data/" + INSTALLER_PACKAGE_NAME + "/";
|
: "/data/data/" + INSTALLER_PACKAGE_NAME + "/";
|
||||||
private static final String INSTANT_RUN_CLASS = "com.android.tools.fd.runtime.BootstrapApplication";
|
private static final String INSTANT_RUN_CLASS = "com.android.tools.fd.runtime.BootstrapApplication";
|
||||||
|
|
@ -89,7 +89,7 @@ public final class XposedInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Try to load all modules defined in <code>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 volatile AtomicBoolean modulesLoaded = new AtomicBoolean(false);
|
||||||
|
|
||||||
|
|
@ -97,7 +97,7 @@ public final class XposedInit {
|
||||||
if (!modulesLoaded.compareAndSet(false, true)) {
|
if (!modulesLoaded.compareAndSet(false, true)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final String filename = 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)) {
|
||||||
Log.e(TAG, "Cannot load any modules because " + filename + " was not found");
|
Log.e(TAG, "Cannot load any modules because " + filename + " was not found");
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue