Fix wrong dex path when using compat mode in some cases

This commit is contained in:
solohsu 2019-02-10 00:45:54 +08:00
parent 285ced4cf9
commit 5a2cf52450
6 changed files with 59 additions and 21 deletions

View File

@ -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) {

View File

@ -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<Member, Method> 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);

View File

@ -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;
}
}

View File

@ -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/";
}

View File

@ -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
* <p>

View File

@ -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 <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);
@ -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");