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 getCachePath(String suffix);
|
||||
|
||||
public static native String getBaseConfigPath();
|
||||
|
||||
public static native String getDataPathPrefix();
|
||||
|
|
|
|||
|
|
@ -68,6 +68,10 @@ namespace edxp {
|
|||
return misc_path_ / "framework" / suffix;
|
||||
}
|
||||
|
||||
inline static auto GetCachePath(const std::string &suffix = {}) {
|
||||
return misc_path_ / "cache" / suffix;
|
||||
}
|
||||
|
||||
inline static auto GetLibSandHookName() {
|
||||
if constexpr(edxp::is64)
|
||||
return GetFrameworkPath("lib64/libsandhook.edxp.so");
|
||||
|
|
|
|||
|
|
@ -53,6 +53,13 @@ namespace edxp {
|
|||
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) {
|
||||
auto result = ConfigManager::GetInstance()->GetBaseConfigPath();
|
||||
return env->NewStringUTF(result.c_str());
|
||||
|
|
@ -80,6 +87,8 @@ namespace edxp {
|
|||
"(Ljava/lang/String;)Ljava/lang/String;"),
|
||||
NATIVE_METHOD(ConfigManager, getPrefsPath,
|
||||
"(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, getModulesList, "()Ljava/lang/String;"),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -230,6 +230,9 @@ if [[ "${VARIANT}" == "SandHook" ]]; then
|
|||
fi
|
||||
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}"
|
||||
if [[ "${IS64BIT}" == true ]]; then
|
||||
mv "${MODPATH}/system/lib64/libriru_edxp.so" "${MODPATH}/system/lib64/${LIB_RIRU_EDXP}"
|
||||
|
|
|
|||
|
|
@ -1,11 +1,9 @@
|
|||
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.util.Utils;
|
||||
|
||||
import java.io.File;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
|
@ -16,19 +14,14 @@ import external.com.android.dx.TypeId;
|
|||
|
||||
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() {
|
||||
if (!IN_MEMORY_DEX_ELIGIBLE) {
|
||||
return false;
|
||||
static {
|
||||
File cacheDir = new File(ConfigManager.getCachePath(""));
|
||||
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) {
|
||||
|
|
|
|||
|
|
@ -15,17 +15,11 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||
import de.robv.android.xposed.EdHooker;
|
||||
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 {
|
||||
|
||||
private static final HashMap<Member, EdHooker> hookedInfo = new HashMap<>();
|
||||
private static final HookerDexMaker dexMaker = new HookerDexMaker();
|
||||
private static final AtomicBoolean dexPathInited = new AtomicBoolean(false);
|
||||
private static File dexDir;
|
||||
private static File dexOptDir;
|
||||
|
||||
/**
|
||||
|
|
@ -50,46 +44,16 @@ public final class DynamicBridge {
|
|||
DexLog.d("start to generate class for: " + hookMethod);
|
||||
long startTime = System.nanoTime();
|
||||
try {
|
||||
// for Android Oreo and later use InMemoryClassLoader
|
||||
if (!shouldUseInMemoryHook()) {
|
||||
setupDexCachePath();
|
||||
}
|
||||
dexMaker.start(hookMethod, additionalHookInfo,
|
||||
hookMethod.getDeclaringClass().getClassLoader(), getDexDirPath());
|
||||
hookMethod.getDeclaringClass().getClassLoader());
|
||||
hookedInfo.put(hookMethod, dexMaker.getHooker());
|
||||
} 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();
|
||||
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) {
|
||||
|
||||
if (member instanceof Method) {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import android.annotation.TargetApi;
|
|||
import android.os.Build;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.elderdrivers.riru.edxp.config.ConfigManager;
|
||||
import com.elderdrivers.riru.edxp.core.yahfa.HookMain;
|
||||
import com.elderdrivers.riru.edxp.util.ProxyClassLoader;
|
||||
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.MethodId;
|
||||
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.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.getObjTypeIdIfPrimitive;
|
||||
|
||||
|
|
@ -69,7 +72,6 @@ public class HookerDexMaker {
|
|||
private Class<?> mHookClass;
|
||||
private Method mHookMethod;
|
||||
private Method mBackupMethod;
|
||||
private String mDexDirPath;
|
||||
private EdHooker mHooker;
|
||||
|
||||
private static TypeId<?>[] getParameterTypeIds(Class<?>[] parameterTypes, boolean isStatic) {
|
||||
|
|
@ -101,7 +103,7 @@ public class HookerDexMaker {
|
|||
}
|
||||
|
||||
public void start(Member member, XposedBridge.AdditionalHookInfo hookInfo,
|
||||
ClassLoader appClassLoader, String dexDirPath) throws Exception {
|
||||
ClassLoader appClassLoader) throws Exception {
|
||||
if (member instanceof Method) {
|
||||
Method method = (Method) member;
|
||||
mIsStatic = Modifier.isStatic(method.getModifiers());
|
||||
|
|
@ -132,7 +134,6 @@ public class HookerDexMaker {
|
|||
}
|
||||
mMember = member;
|
||||
mHookInfo = hookInfo;
|
||||
mDexDirPath = dexDirPath;
|
||||
if (appClassLoader == null
|
||||
|| appClassLoader.getClass().getName().equals("java.lang.BootClassLoader")) {
|
||||
mAppClassLoader = getClass().getClassLoader();
|
||||
|
|
@ -145,27 +146,36 @@ public class HookerDexMaker {
|
|||
|
||||
@TargetApi(Build.VERSION_CODES.O)
|
||||
private void doMake(String hookedClassName) throws Exception {
|
||||
final boolean useInMemoryCl = TextUtils.isEmpty(mDexDirPath);
|
||||
mDexMaker = new DexMaker();
|
||||
ClassLoader loader;
|
||||
ClassLoader loader = null;
|
||||
// Generate a Hooker class.
|
||||
String className = CLASS_NAME_PREFIX;
|
||||
if (!useInMemoryCl) {
|
||||
// if not using InMemoryDexClassLoader, className is also used as dex file name
|
||||
// so it should be different from each other
|
||||
String suffix = DexMakerUtils.getSha1Hex(mMember.toString());
|
||||
if (TextUtils.isEmpty(suffix)) { // just in case
|
||||
suffix = String.valueOf(sClassNameSuffix.getAndIncrement());
|
||||
}
|
||||
className = className + suffix;
|
||||
if (!new File(mDexDirPath, className).exists()) {
|
||||
// if file exists, reuse it and skip generating
|
||||
doGenerate(className);
|
||||
}
|
||||
// load dex file from disk
|
||||
loader = mDexMaker.generateAndLoad(mAppClassLoader, new File(mDexDirPath), className);
|
||||
} else {
|
||||
boolean usedCache = false;
|
||||
if (canCache) {
|
||||
try {
|
||||
// className is also used as dex file name
|
||||
// so it should be different from each other
|
||||
String suffix = DexMakerUtils.getSha1Hex(mMember.toString());
|
||||
className = className + suffix;
|
||||
String dexFileName = className + ".jar";
|
||||
File dexFile = new File(ConfigManager.getCachePath(dexFileName));
|
||||
if (!dexFile.exists()) {
|
||||
// if file exists, reuse it and skip generating
|
||||
DexLog.d("Generating " + dexFileName);
|
||||
doGenerate(className);
|
||||
loader = mDexMaker.generateAndLoad(mAppClassLoader, new File(ConfigManager.getCachePath("")), dexFileName, false);
|
||||
dexFile.setWritable(true, false);
|
||||
dexFile.setReadable(true, false);
|
||||
} 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
|
||||
DexLog.d("Generating in memory");
|
||||
if(BuildConfig.DEBUG)
|
||||
className = className + hookedClassName.replace(".", "/");
|
||||
doGenerate(className);
|
||||
|
|
|
|||
Loading…
Reference in New Issue