Enable yahfa's cache
This commit is contained in:
parent
ba6c61fc1e
commit
8c838c6d6d
|
|
@ -45,6 +45,8 @@ public class ConfigManager {
|
||||||
|
|
||||||
public static native String getPrefsPath(String suffix);
|
public static native String getPrefsPath(String suffix);
|
||||||
|
|
||||||
|
public static native String getCachePath(String suffix);
|
||||||
|
|
||||||
public static native String getBaseConfigPath();
|
public static native String getBaseConfigPath();
|
||||||
|
|
||||||
public static native String getDataPathPrefix();
|
public static native String getDataPathPrefix();
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,10 @@ namespace edxp {
|
||||||
return misc_path_ / "framework" / suffix;
|
return misc_path_ / "framework" / suffix;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline static auto GetCachePath(const std::string &suffix = {}) {
|
||||||
|
return misc_path_ / "cache" / suffix;
|
||||||
|
}
|
||||||
|
|
||||||
inline static auto GetLibSandHookName() {
|
inline static auto GetLibSandHookName() {
|
||||||
if constexpr(edxp::is64)
|
if constexpr(edxp::is64)
|
||||||
return GetFrameworkPath("lib64/libsandhook.edxp.so");
|
return GetFrameworkPath("lib64/libsandhook.edxp.so");
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,13 @@ namespace edxp {
|
||||||
return env->NewStringUTF(result.c_str());
|
return env->NewStringUTF(result.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static jstring ConfigManager_getCachePath(JNI_START, jstring jSuffix) {
|
||||||
|
const char *suffix = env->GetStringUTFChars(jSuffix, JNI_FALSE);
|
||||||
|
auto result = ConfigManager::GetCachePath(suffix);
|
||||||
|
env->ReleaseStringUTFChars(jSuffix, suffix);
|
||||||
|
return env->NewStringUTF(result.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
static jstring ConfigManager_getBaseConfigPath(JNI_START) {
|
static jstring ConfigManager_getBaseConfigPath(JNI_START) {
|
||||||
auto result = ConfigManager::GetInstance()->GetBaseConfigPath();
|
auto result = ConfigManager::GetInstance()->GetBaseConfigPath();
|
||||||
return env->NewStringUTF(result.c_str());
|
return env->NewStringUTF(result.c_str());
|
||||||
|
|
@ -80,6 +87,8 @@ namespace edxp {
|
||||||
"(Ljava/lang/String;)Ljava/lang/String;"),
|
"(Ljava/lang/String;)Ljava/lang/String;"),
|
||||||
NATIVE_METHOD(ConfigManager, getPrefsPath,
|
NATIVE_METHOD(ConfigManager, getPrefsPath,
|
||||||
"(Ljava/lang/String;)Ljava/lang/String;"),
|
"(Ljava/lang/String;)Ljava/lang/String;"),
|
||||||
|
NATIVE_METHOD(ConfigManager, getCachePath,
|
||||||
|
"(Ljava/lang/String;)Ljava/lang/String;"),
|
||||||
NATIVE_METHOD(ConfigManager, getBaseConfigPath,"()Ljava/lang/String;"),
|
NATIVE_METHOD(ConfigManager, getBaseConfigPath,"()Ljava/lang/String;"),
|
||||||
NATIVE_METHOD(ConfigManager, getModulesList, "()Ljava/lang/String;"),
|
NATIVE_METHOD(ConfigManager, getModulesList, "()Ljava/lang/String;"),
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -230,6 +230,9 @@ if [[ "${VARIANT}" == "SandHook" ]]; then
|
||||||
fi
|
fi
|
||||||
set_perm_recursive /data/misc/$MISC_PATH/framework root root 0755 0644 "u:object_r:magisk_file:s0" || abortC "! ${LANG_CUST_ERR_PERM}"
|
set_perm_recursive /data/misc/$MISC_PATH/framework root root 0755 0644 "u:object_r:magisk_file:s0" || abortC "! ${LANG_CUST_ERR_PERM}"
|
||||||
|
|
||||||
|
mkdir -p /data/misc/$MISC_PATH/cache
|
||||||
|
set_perm /data/misc/$MISC_PATH/cache root root 0777 "u:object_r:magisk_file:s0" || abortC "! ${LANG_CUST_ERR_PERM}"
|
||||||
|
|
||||||
mv "${MODPATH}/system/lib/libriru_edxp.so" "${MODPATH}/system/lib/${LIB_RIRU_EDXP}"
|
mv "${MODPATH}/system/lib/libriru_edxp.so" "${MODPATH}/system/lib/${LIB_RIRU_EDXP}"
|
||||||
if [[ "${IS64BIT}" == true ]]; then
|
if [[ "${IS64BIT}" == true ]]; then
|
||||||
mv "${MODPATH}/system/lib64/libriru_edxp.so" "${MODPATH}/system/lib64/${LIB_RIRU_EDXP}"
|
mv "${MODPATH}/system/lib64/libriru_edxp.so" "${MODPATH}/system/lib64/${LIB_RIRU_EDXP}"
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,9 @@
|
||||||
package com.elderdrivers.riru.edxp.yahfa.dexmaker;
|
package com.elderdrivers.riru.edxp.yahfa.dexmaker;
|
||||||
|
|
||||||
import android.app.AndroidAppHelper;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.text.TextUtils;
|
|
||||||
|
|
||||||
import com.elderdrivers.riru.edxp.config.ConfigManager;
|
import com.elderdrivers.riru.edxp.config.ConfigManager;
|
||||||
|
import com.elderdrivers.riru.edxp.util.Utils;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.security.MessageDigest;
|
import java.security.MessageDigest;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
@ -16,19 +14,14 @@ import external.com.android.dx.TypeId;
|
||||||
|
|
||||||
public class DexMakerUtils {
|
public class DexMakerUtils {
|
||||||
|
|
||||||
private static final boolean IN_MEMORY_DEX_ELIGIBLE = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O;
|
public static boolean canCache = true;
|
||||||
|
|
||||||
public static boolean shouldUseInMemoryHook() {
|
static {
|
||||||
if (!IN_MEMORY_DEX_ELIGIBLE) {
|
File cacheDir = new File(ConfigManager.getCachePath(""));
|
||||||
return false;
|
if(!cacheDir.canRead() || !cacheDir.canWrite()) {
|
||||||
|
Utils.logW("Cache disabled");
|
||||||
|
canCache = false;
|
||||||
}
|
}
|
||||||
String packageName = AndroidAppHelper.currentPackageName();
|
|
||||||
if (TextUtils.isEmpty(packageName)) { //default to true
|
|
||||||
DexLog.w("packageName is empty, processName=" + ConfigManager.appProcessName
|
|
||||||
+ ", appDataDir=" + ConfigManager.appDataDir);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return !ConfigManager.shouldUseCompatMode(packageName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void autoBoxIfNecessary(Code code, Local<Object> target, Local source) {
|
public static void autoBoxIfNecessary(Code code, Local<Object> target, Local source) {
|
||||||
|
|
|
||||||
|
|
@ -15,17 +15,11 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import de.robv.android.xposed.EdHooker;
|
import de.robv.android.xposed.EdHooker;
|
||||||
import de.robv.android.xposed.XposedBridge;
|
import de.robv.android.xposed.XposedBridge;
|
||||||
|
|
||||||
import static com.elderdrivers.riru.edxp.util.FileUtils.getDataPathPrefix;
|
|
||||||
import static com.elderdrivers.riru.edxp.util.FileUtils.getPackageName;
|
|
||||||
import static com.elderdrivers.riru.edxp.util.ProcessUtils.getCurrentProcessName;
|
|
||||||
import static com.elderdrivers.riru.edxp.yahfa.dexmaker.DexMakerUtils.shouldUseInMemoryHook;
|
|
||||||
|
|
||||||
public final class DynamicBridge {
|
public final class DynamicBridge {
|
||||||
|
|
||||||
private static final HashMap<Member, EdHooker> hookedInfo = new HashMap<>();
|
private static final HashMap<Member, EdHooker> 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 File dexDir;
|
|
||||||
private static File dexOptDir;
|
private static File dexOptDir;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -50,46 +44,16 @@ public final class DynamicBridge {
|
||||||
DexLog.d("start to generate class for: " + hookMethod);
|
DexLog.d("start to generate class for: " + hookMethod);
|
||||||
long startTime = System.nanoTime();
|
long startTime = System.nanoTime();
|
||||||
try {
|
try {
|
||||||
// for Android Oreo and later use InMemoryClassLoader
|
|
||||||
if (!shouldUseInMemoryHook()) {
|
|
||||||
setupDexCachePath();
|
|
||||||
}
|
|
||||||
dexMaker.start(hookMethod, additionalHookInfo,
|
dexMaker.start(hookMethod, additionalHookInfo,
|
||||||
hookMethod.getDeclaringClass().getClassLoader(), getDexDirPath());
|
hookMethod.getDeclaringClass().getClassLoader());
|
||||||
hookedInfo.put(hookMethod, dexMaker.getHooker());
|
hookedInfo.put(hookMethod, dexMaker.getHooker());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
DexLog.e("error occur when generating dex. dexDir=" + dexDir, e);
|
DexLog.e("error occur when generating dex.", e);
|
||||||
}
|
}
|
||||||
long endTime = System.nanoTime();
|
long endTime = System.nanoTime();
|
||||||
DexLog.d("generated class for " + hookMethod + " in " + ((endTime-startTime) * 1.e-6) + "ms");
|
DexLog.d("generated class for " + hookMethod + " in " + ((endTime-startTime) * 1.e-6) + "ms");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String getDexDirPath() {
|
|
||||||
if (dexDir == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return dexDir.getAbsolutePath();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void setupDexCachePath() {
|
|
||||||
// using file based DexClassLoader
|
|
||||||
if (!dexPathInited.compareAndSet(false, true)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
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(ConfigManager.appDataDir) + "/";
|
|
||||||
dexDir = new File(fixedAppDataDir, "/cache/edhookers/"
|
|
||||||
+ getCurrentProcessName(ConfigManager.appProcessName).replace(":", "_") + "/");
|
|
||||||
dexOptDir = new File(dexDir, "oat");
|
|
||||||
dexDir.mkdirs();
|
|
||||||
DexLog.d(ConfigManager.appProcessName + " deleting dir: " + dexOptDir.getAbsolutePath());
|
|
||||||
} catch (Throwable throwable) {
|
|
||||||
DexLog.e("error when init dex path", throwable);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean checkMember(Member member) {
|
private static boolean checkMember(Member member) {
|
||||||
|
|
||||||
if (member instanceof Method) {
|
if (member instanceof Method) {
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import android.annotation.TargetApi;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
|
import com.elderdrivers.riru.edxp.config.ConfigManager;
|
||||||
import com.elderdrivers.riru.edxp.core.yahfa.HookMain;
|
import com.elderdrivers.riru.edxp.core.yahfa.HookMain;
|
||||||
import com.elderdrivers.riru.edxp.util.ProxyClassLoader;
|
import com.elderdrivers.riru.edxp.util.ProxyClassLoader;
|
||||||
import com.elderdrivers.riru.edxp.yahfa.BuildConfig;
|
import com.elderdrivers.riru.edxp.yahfa.BuildConfig;
|
||||||
|
|
@ -26,9 +27,11 @@ import external.com.android.dx.FieldId;
|
||||||
import external.com.android.dx.Local;
|
import external.com.android.dx.Local;
|
||||||
import external.com.android.dx.MethodId;
|
import external.com.android.dx.MethodId;
|
||||||
import external.com.android.dx.TypeId;
|
import external.com.android.dx.TypeId;
|
||||||
|
import pxb.android.arsc.Config;
|
||||||
|
|
||||||
import static com.elderdrivers.riru.edxp.yahfa.dexmaker.DexMakerUtils.autoBoxIfNecessary;
|
import static com.elderdrivers.riru.edxp.yahfa.dexmaker.DexMakerUtils.autoBoxIfNecessary;
|
||||||
import static com.elderdrivers.riru.edxp.yahfa.dexmaker.DexMakerUtils.autoUnboxIfNecessary;
|
import static com.elderdrivers.riru.edxp.yahfa.dexmaker.DexMakerUtils.autoUnboxIfNecessary;
|
||||||
|
import static com.elderdrivers.riru.edxp.yahfa.dexmaker.DexMakerUtils.canCache;
|
||||||
import static com.elderdrivers.riru.edxp.yahfa.dexmaker.DexMakerUtils.createResultLocals;
|
import static com.elderdrivers.riru.edxp.yahfa.dexmaker.DexMakerUtils.createResultLocals;
|
||||||
import static com.elderdrivers.riru.edxp.yahfa.dexmaker.DexMakerUtils.getObjTypeIdIfPrimitive;
|
import static com.elderdrivers.riru.edxp.yahfa.dexmaker.DexMakerUtils.getObjTypeIdIfPrimitive;
|
||||||
|
|
||||||
|
|
@ -69,7 +72,6 @@ public class HookerDexMaker {
|
||||||
private Class<?> mHookClass;
|
private Class<?> mHookClass;
|
||||||
private Method mHookMethod;
|
private Method mHookMethod;
|
||||||
private Method mBackupMethod;
|
private Method mBackupMethod;
|
||||||
private String mDexDirPath;
|
|
||||||
private EdHooker mHooker;
|
private EdHooker mHooker;
|
||||||
|
|
||||||
private static TypeId<?>[] getParameterTypeIds(Class<?>[] parameterTypes, boolean isStatic) {
|
private static TypeId<?>[] getParameterTypeIds(Class<?>[] parameterTypes, boolean isStatic) {
|
||||||
|
|
@ -101,7 +103,7 @@ public class HookerDexMaker {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void start(Member member, XposedBridge.AdditionalHookInfo hookInfo,
|
public void start(Member member, XposedBridge.AdditionalHookInfo hookInfo,
|
||||||
ClassLoader appClassLoader, String dexDirPath) throws Exception {
|
ClassLoader appClassLoader) throws Exception {
|
||||||
if (member instanceof Method) {
|
if (member instanceof Method) {
|
||||||
Method method = (Method) member;
|
Method method = (Method) member;
|
||||||
mIsStatic = Modifier.isStatic(method.getModifiers());
|
mIsStatic = Modifier.isStatic(method.getModifiers());
|
||||||
|
|
@ -132,7 +134,6 @@ public class HookerDexMaker {
|
||||||
}
|
}
|
||||||
mMember = member;
|
mMember = member;
|
||||||
mHookInfo = hookInfo;
|
mHookInfo = hookInfo;
|
||||||
mDexDirPath = dexDirPath;
|
|
||||||
if (appClassLoader == null
|
if (appClassLoader == null
|
||||||
|| appClassLoader.getClass().getName().equals("java.lang.BootClassLoader")) {
|
|| appClassLoader.getClass().getName().equals("java.lang.BootClassLoader")) {
|
||||||
mAppClassLoader = getClass().getClassLoader();
|
mAppClassLoader = getClass().getClassLoader();
|
||||||
|
|
@ -145,27 +146,36 @@ public class HookerDexMaker {
|
||||||
|
|
||||||
@TargetApi(Build.VERSION_CODES.O)
|
@TargetApi(Build.VERSION_CODES.O)
|
||||||
private void doMake(String hookedClassName) throws Exception {
|
private void doMake(String hookedClassName) throws Exception {
|
||||||
final boolean useInMemoryCl = TextUtils.isEmpty(mDexDirPath);
|
|
||||||
mDexMaker = new DexMaker();
|
mDexMaker = new DexMaker();
|
||||||
ClassLoader loader;
|
ClassLoader loader = null;
|
||||||
// Generate a Hooker class.
|
// Generate a Hooker class.
|
||||||
String className = CLASS_NAME_PREFIX;
|
String className = CLASS_NAME_PREFIX;
|
||||||
if (!useInMemoryCl) {
|
boolean usedCache = false;
|
||||||
// if not using InMemoryDexClassLoader, className is also used as dex file name
|
if (canCache) {
|
||||||
|
try {
|
||||||
|
// className is also used as dex file name
|
||||||
// so it should be different from each other
|
// so it should be different from each other
|
||||||
String suffix = DexMakerUtils.getSha1Hex(mMember.toString());
|
String suffix = DexMakerUtils.getSha1Hex(mMember.toString());
|
||||||
if (TextUtils.isEmpty(suffix)) { // just in case
|
|
||||||
suffix = String.valueOf(sClassNameSuffix.getAndIncrement());
|
|
||||||
}
|
|
||||||
className = className + suffix;
|
className = className + suffix;
|
||||||
if (!new File(mDexDirPath, className).exists()) {
|
String dexFileName = className + ".jar";
|
||||||
|
File dexFile = new File(ConfigManager.getCachePath(dexFileName));
|
||||||
|
if (!dexFile.exists()) {
|
||||||
// if file exists, reuse it and skip generating
|
// if file exists, reuse it and skip generating
|
||||||
|
DexLog.d("Generating " + dexFileName);
|
||||||
doGenerate(className);
|
doGenerate(className);
|
||||||
}
|
loader = mDexMaker.generateAndLoad(mAppClassLoader, new File(ConfigManager.getCachePath("")), dexFileName, false);
|
||||||
// load dex file from disk
|
dexFile.setWritable(true, false);
|
||||||
loader = mDexMaker.generateAndLoad(mAppClassLoader, new File(mDexDirPath), className);
|
dexFile.setReadable(true, false);
|
||||||
} else {
|
} else {
|
||||||
|
DexLog.d("Using cache " + dexFileName);
|
||||||
|
loader = mDexMaker.loadClassDirect(mAppClassLoader, new File(ConfigManager.getCachePath("")), dexFileName);
|
||||||
|
}
|
||||||
|
usedCache = true;
|
||||||
|
} catch (Throwable ignored) {}
|
||||||
|
}
|
||||||
|
if (!usedCache) {
|
||||||
// do everything in memory
|
// do everything in memory
|
||||||
|
DexLog.d("Generating in memory");
|
||||||
if(BuildConfig.DEBUG)
|
if(BuildConfig.DEBUG)
|
||||||
className = className + hookedClassName.replace(".", "/");
|
className = className + hookedClassName.replace(".", "/");
|
||||||
doGenerate(className);
|
doGenerate(className);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue