From 5a2cf5245056abafe1245bc4fc6a5f173f3110e4 Mon Sep 17 00:00:00 2001 From: solohsu Date: Sun, 10 Feb 2019 00:45:54 +0800 Subject: [PATCH] Fix wrong dex path when using compat mode in some cases --- .../com/elderdrivers/riru/xposed/Main.java | 11 +++++-- .../riru/xposed/dexmaker/DynamicBridge.java | 33 +++++++++++-------- .../riru/xposed/entry/Router.java | 4 +-- .../riru/xposed/util/FileUtils.java | 13 ++++++++ .../riru/xposed/util/ProcessUtils.java | 13 ++++++++ .../de/robv/android/xposed/XposedInit.java | 6 ++-- 6 files changed, 59 insertions(+), 21 deletions(-) diff --git a/Bridge/src/main/java/com/elderdrivers/riru/xposed/Main.java b/Bridge/src/main/java/com/elderdrivers/riru/xposed/Main.java index 0fa6e824..2b2ba27b 100644 --- a/Bridge/src/main/java/com/elderdrivers/riru/xposed/Main.java +++ b/Bridge/src/main/java/com/elderdrivers/riru/xposed/Main.java @@ -5,6 +5,7 @@ import android.os.Build; import com.elderdrivers.riru.common.KeepAll; import com.elderdrivers.riru.xposed.core.HookMethodResolver; +import com.elderdrivers.riru.xposed.dexmaker.DynamicBridge; import com.elderdrivers.riru.xposed.entry.Router; import java.lang.reflect.Method; @@ -55,9 +56,11 @@ public class Main implements KeepAll { sIsGlobalMode = isGlobalMode; sIsDynamicModules = isDynamicModules; if (isGlobalMode) { + // do bootstrap hooking only once in zygote process Router.onProcessForked(false); } - if (!sIsDynamicModules) { + if (!isDynamicModules) { + // load modules only once in zygote process Router.loadModulesSafely(); } } @@ -65,11 +68,14 @@ public class Main implements KeepAll { public static void forkAndSpecializePost(int pid, String appDataDir) { // Utils.logD(sForkAndSpecializePramsStr + " = " + pid); if (pid == 0) { + DynamicBridge.onForkPost(); // in app process if (!sIsGlobalMode) { + // do bootstrap hooking separately for each app process Router.onProcessForked(false); } if (sIsDynamicModules) { + // load modules for each app process on its forked Router.loadModulesSafely(); } } else { @@ -83,7 +89,8 @@ public class Main implements KeepAll { // sForkSystemServerPramsStr = String.format("Zygote#forkSystemServer(%d, %d, %s, %d, %s, %d, %d)", // uid, gid, Arrays.toString(gids), debugFlags, Arrays.toString(rlimits), // permittedCapabilities, effectiveCapabilities); - sAppDataDir = getDataPathPrefix() + "android/"; + sAppDataDir = getDataPathPrefix() + "android"; + // system_server process doesn't need sIsGlobalMode and sIsDynamicModules } public static void forkSystemServerPost(int pid) { diff --git a/Bridge/src/main/java/com/elderdrivers/riru/xposed/dexmaker/DynamicBridge.java b/Bridge/src/main/java/com/elderdrivers/riru/xposed/dexmaker/DynamicBridge.java index 7aeae11e..d9839a41 100644 --- a/Bridge/src/main/java/com/elderdrivers/riru/xposed/dexmaker/DynamicBridge.java +++ b/Bridge/src/main/java/com/elderdrivers/riru/xposed/dexmaker/DynamicBridge.java @@ -1,7 +1,5 @@ package com.elderdrivers.riru.xposed.dexmaker; -import android.app.AndroidAppHelper; - import com.elderdrivers.riru.xposed.Main; 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.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 { private static final HashMap hookedInfo = new HashMap<>(); private static final HookerDexMaker dexMaker = new HookerDexMaker(); private static final AtomicBoolean dexPathInited = new AtomicBoolean(false); - private static final File dexDir; - private static final File dexOptDir; + private static File dexDir; + private static File dexOptDir; - static { - // 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() + AndroidAppHelper.currentPackageName() + "/"; - dexDir = new File(fixedAppDataDir, "/cache/edhookers/" - + Main.sAppProcessName.replace(":", "_") + "/"); - dexOptDir = new File(dexDir, "oat"); + public static void onForkPost() { + dexPathInited.set(false); } public static synchronized void hookMethod(Member hookMethod, XposedBridge.AdditionalHookInfo additionalHookInfo) { @@ -51,20 +46,30 @@ public final class DynamicBridge { try { // for Android Oreo and later use InMemoryClassLoader if (!shouldUseInMemoryHook()) { - // under Android Oreo, using DexClassLoader + // using file based DexClassLoader if (dexPathInited.compareAndSet(false, true)) { // delete previous compiled dex to prevent potential crashing // TODO find a way to reuse them in consideration of performance 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(); DexLog.d(Main.sAppProcessName + " deleting dir: " + dexOptDir.getAbsolutePath()); - FileUtils.delete(dexOptDir); + try { + FileUtils.delete(dexOptDir); + } catch (Throwable throwable) { + } } catch (Throwable throwable) { + DexLog.e("error when init dex path", throwable); } } } dexMaker.start(hookMethod, additionalHookInfo, - hookMethod.getDeclaringClass().getClassLoader(), dexDir.getAbsolutePath()); + hookMethod.getDeclaringClass().getClassLoader(), dexDir == null ? null : dexDir.getAbsolutePath()); hookedInfo.put(hookMethod, dexMaker.getCallBackupMethod()); } catch (Exception e) { DexLog.e("error occur when generating dex. dexDir=" + dexDir, e); diff --git a/Bridge/src/main/java/com/elderdrivers/riru/xposed/entry/Router.java b/Bridge/src/main/java/com/elderdrivers/riru/xposed/entry/Router.java index b2f34de2..76b78546 100644 --- a/Bridge/src/main/java/com/elderdrivers/riru/xposed/entry/Router.java +++ b/Bridge/src/main/java/com/elderdrivers/riru/xposed/entry/Router.java @@ -13,11 +13,11 @@ import de.robv.android.xposed.XposedInit; public class Router { public static void onProcessForked(boolean isSystem) { - // Initialize the Xposed framework and modules + // Initialize the Xposed framework try { XposedInit.initForZygote(isSystem); } catch (Throwable t) { - Utils.logE("Errors during Xposed initialization", t); + Utils.logE("error during Xposed initialization", t); XposedBridge.disableHooks = true; } } diff --git a/Bridge/src/main/java/com/elderdrivers/riru/xposed/util/FileUtils.java b/Bridge/src/main/java/com/elderdrivers/riru/xposed/util/FileUtils.java index e85a66d4..dc34d07d 100644 --- a/Bridge/src/main/java/com/elderdrivers/riru/xposed/util/FileUtils.java +++ b/Bridge/src/main/java/com/elderdrivers/riru/xposed/util/FileUtils.java @@ -1,6 +1,7 @@ package com.elderdrivers.riru.xposed.util; import android.os.Build; +import android.text.TextUtils; import java.io.BufferedReader; 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() { return IS_USING_PROTECTED_STORAGE ? "/data/user_de/0/" : "/data/data/"; } diff --git a/Bridge/src/main/java/com/elderdrivers/riru/xposed/util/ProcessUtils.java b/Bridge/src/main/java/com/elderdrivers/riru/xposed/util/ProcessUtils.java index b7c474e2..2b0c44c7 100644 --- a/Bridge/src/main/java/com/elderdrivers/riru/xposed/util/ProcessUtils.java +++ b/Bridge/src/main/java/com/elderdrivers/riru/xposed/util/ProcessUtils.java @@ -1,5 +1,10 @@ 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.File; import java.io.FileInputStream; @@ -7,6 +12,14 @@ import java.io.InputStreamReader; 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 *

diff --git a/Bridge/src/main/java/de/robv/android/xposed/XposedInit.java b/Bridge/src/main/java/de/robv/android/xposed/XposedInit.java index 371b3008..2502b61d 100644 --- a/Bridge/src/main/java/de/robv/android/xposed/XposedInit.java +++ b/Bridge/src/main/java/de/robv/android/xposed/XposedInit.java @@ -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_LEGACY_PACKAGE_NAME = "de.robv.android.xposed.installer"; @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/data/" + INSTALLER_PACKAGE_NAME + "/"; 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 BASE_DIR/conf/modules.list + * Try to load all modules defined in INSTALLER_DATA_BASE_DIR/conf/modules.list */ private static volatile AtomicBoolean modulesLoaded = new AtomicBoolean(false); @@ -97,7 +97,7 @@ public final class XposedInit { if (!modulesLoaded.compareAndSet(false, true)) { return; } - final String filename = BASE_DIR + "conf/modules.list"; + final String filename = INSTALLER_DATA_BASE_DIR + "conf/modules.list"; BaseService service = SELinuxHelper.getAppDataFileService(); if (!service.checkFileExists(filename)) { Log.e(TAG, "Cannot load any modules because " + filename + " was not found");