[core] Refine dexmaker cache stategy for YAHFA (#187)

* [core] Refine dexmaker cache stategy for YAHFA

* Delete old when old cache is invalid
This commit is contained in:
LoveSy 2021-02-24 22:13:24 +08:00 committed by GitHub
parent d0bd6c1be3
commit cc0afb03e8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 34 additions and 25 deletions

View File

@ -150,7 +150,6 @@ public class ConfigManager {
// for system server, cache is not yet ready, we need to query database for it // for system server, cache is not yet ready, we need to query database for it
public boolean shouldSkipSystemServer() { public boolean shouldSkipSystemServer() {
try (Cursor cursor = db.query("scope INNER JOIN modules ON scope.mid = modules.mid", new String[]{"modules.mid"}, "app_pkg_name=? AND enabled=1", new String[]{"android"}, null, null, null)) { try (Cursor cursor = db.query("scope INNER JOIN modules ON scope.mid = modules.mid", new String[]{"modules.mid"}, "app_pkg_name=? AND enabled=1", new String[]{"android"}, null, null, null)) {
Log.e(TAG, "ZHEER2");
return cursor == null || !cursor.moveToNext(); return cursor == null || !cursor.moveToNext();
} }
} }

View File

@ -42,7 +42,6 @@ public class LSPosedService extends ILSPosedService.Stub {
return null; return null;
} }
if (uid == 1000 && processName.equals("android")) { if (uid == 1000 && processName.equals("android")) {
Log.e(TAG, "ZHEER");
if (ConfigManager.getInstance().shouldSkipSystemServer()) if (ConfigManager.getInstance().shouldSkipSystemServer())
return null; return null;
else else

View File

@ -155,45 +155,54 @@ public class HookerDexMaker {
@SuppressWarnings("ResultOfMethodCallIgnored") @SuppressWarnings("ResultOfMethodCallIgnored")
@TargetApi(Build.VERSION_CODES.O) @TargetApi(Build.VERSION_CODES.O)
private void doMake(String hookedClassName) throws Exception { private void doMake(String hookedClassName) throws Exception {
ClassLoader loader = null; Class<?> hookClass = null;
// Generate a Hooker class. // Generate a Hooker class.
String className = CLASS_NAME_PREFIX; String className = CLASS_NAME_PREFIX;
boolean usedCache = false;
if (canCache) { if (canCache) {
try { mDexMaker = new DexMaker();
mDexMaker = new DexMaker(); // className is also used as dex file name
// 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()); className = className + suffix;
className = className + suffix; String dexFileName = className + ".jar";
String dexFileName = className + ".jar"; File dexFile = new File(serviceClient.getCachePath(dexFileName));
File dexFile = new File(serviceClient.getCachePath(dexFileName)); if (dexFile.exists()) {
if (!dexFile.exists()) { try {
// if file exists, reuse it and skip generating // if file exists, reuse it and skip generating
DexLog.d("Generating " + dexFileName); DexLog.d("Using cache " + dexFileName);
ClassLoader loader = mDexMaker.loadClassDirect(mAppClassLoader, dexFile.getParentFile(), dexFileName);
hookClass = Class.forName(className.replace("/", "."), true, loader);
} catch (Throwable ignored) {
}
}
if (hookClass == null) {
try {
DexLog.d("cache not hit, generating " + dexFileName);
doGenerate(className); doGenerate(className);
loader = mDexMaker.generateAndLoad(mAppClassLoader, new File(serviceClient.getCachePath("")), dexFileName, false); ClassLoader loader = mDexMaker.generateAndLoad(mAppClassLoader, dexFile.getParentFile(), dexFileName, true);
dexFile.setWritable(true, false); dexFile.setWritable(true, false);
dexFile.setReadable(true, false); dexFile.setReadable(true, false);
} else { hookClass = Class.forName(className.replace("/", "."), true, loader);
DexLog.d("Using cache " + dexFileName); } catch (Throwable ignored) {
loader = mDexMaker.loadClassDirect(mAppClassLoader, new File(serviceClient.getCachePath("")), dexFileName);
} }
usedCache = true; }
} catch (Throwable ignored) {}
} }
if (!usedCache) { if (hookClass == null) {
// do everything in memory // do everything in memory
DexLog.d("Generating in memory"); DexLog.d("Falling back to generate in memory");
if (BuildConfig.DEBUG) if (BuildConfig.DEBUG)
className = className + hookedClassName.replace(".", "/"); className = className + hookedClassName.replace(".", "/");
mDexMaker = new DexMaker(); mDexMaker = new DexMaker();
doGenerate(className); doGenerate(className);
byte[] dexBytes = mDexMaker.generate(); byte[] dexBytes = mDexMaker.generate();
loader = new InMemoryDexClassLoader(ByteBuffer.wrap(dexBytes), mAppClassLoader); ClassLoader loader = new InMemoryDexClassLoader(ByteBuffer.wrap(dexBytes), mAppClassLoader);
hookClass = Class.forName(className.replace("/", "."), true, loader);
} }
Class<?> hookClass = Class.forName(className.replace("/", "."), true, loader); if (hookClass == null) {
DexLog.e("Unable to generate hooker class. This should not happen. Skipping...");
return;
}
// Execute our newly-generated code in-process. // Execute our newly-generated code in-process.
Method backupMethod = hookClass.getMethod(METHOD_NAME_BACKUP, mActualParameterTypes); Method backupMethod = hookClass.getMethod(METHOD_NAME_BACKUP, mActualParameterTypes);
mHooker = new LspHooker(mHookInfo, mMember, backupMethod); mHooker = new LspHooker(mHookInfo, mMember, backupMethod);
@ -212,7 +221,9 @@ public class HookerDexMaker {
generateHookMethod(); generateHookMethod();
} }
public LspHooker getHooker() {return mHooker;} public LspHooker getHooker() {
return mHooker;
}
private void generateFields() { private void generateFields() {
mHookerFieldId = mHookerTypeId.getField(hookerTypeId, FIELD_NAME_HOOKER); mHookerFieldId = mHookerTypeId.getField(hookerTypeId, FIELD_NAME_HOOKER);