diff --git a/app/src/main/java/org/lsposed/lspatch/appstub/LSPApplicationStub.java b/app/src/main/java/org/lsposed/lspatch/appstub/LSPApplicationStub.java deleted file mode 100644 index a3b4e9c..0000000 --- a/app/src/main/java/org/lsposed/lspatch/appstub/LSPApplicationStub.java +++ /dev/null @@ -1,36 +0,0 @@ -package org.lsposed.lspatch.appstub; - -import android.app.Application; -import android.content.Context; - -import java.io.ByteArrayOutputStream; - -public class LSPApplicationStub extends Application { - - private static byte[] dex = null; - - static { - try (var is = LSPApplicationStub.class.getClassLoader().getResourceAsStream("assets/lsp"); - var os = new ByteArrayOutputStream()) { - byte[] buffer = new byte[8192]; - int n; - while (-1 != (n = is.read(buffer))) { - os.write(buffer, 0, n); - } - dex = os.toByteArray(); - } catch (Throwable e) { - android.util.Log.e("LSPatch", "load dex error", e); - } - System.loadLibrary("lspd"); - } - - @Override - public void onCreate() { - super.onCreate(); - } - - @Override - protected void attachBaseContext(Context base) { - super.attachBaseContext(base); - } -} diff --git a/appstub/src/main/java/org/lsposed/lspatch/appstub/LSPAppComponentFactoryStub.java b/appstub/src/main/java/org/lsposed/lspatch/appstub/LSPAppComponentFactoryStub.java index e01bfe4..ecf6b6d 100644 --- a/appstub/src/main/java/org/lsposed/lspatch/appstub/LSPAppComponentFactoryStub.java +++ b/appstub/src/main/java/org/lsposed/lspatch/appstub/LSPAppComponentFactoryStub.java @@ -28,6 +28,7 @@ public class LSPAppComponentFactoryStub extends AppComponentFactory { private static final String ORIGINAL_APP_COMPONENT_FACTORY_ASSET_PATH = "assets/original_app_component_factory.ini"; private ClassLoader appClassLoader = null; + private ClassLoader lspClassLoader = null; private ClassLoader baseClassLoader = null; private AppComponentFactory originalAppComponentFactory = null; @@ -37,8 +38,7 @@ public class LSPAppComponentFactoryStub extends AppComponentFactory { **/ private void initOriginalAppComponentFactory(ApplicationInfo aInfo) { final String cacheApkPath = aInfo.dataDir + "/cache/origin_apk.bin"; - final String originalAppComponentFactoryClass = - FileUtils.readTextFromInputStream(baseClassLoader.getResourceAsStream(ORIGINAL_APP_COMPONENT_FACTORY_ASSET_PATH)); + final String originalAppComponentFactoryClass = FileUtils.readTextFromInputStream(baseClassLoader.getResourceAsStream(ORIGINAL_APP_COMPONENT_FACTORY_ASSET_PATH)); try { try (InputStream inputStream = baseClassLoader.getResourceAsStream(ORIGINAL_APK_ASSET_PATH)) { @@ -46,10 +46,15 @@ public class LSPAppComponentFactoryStub extends AppComponentFactory { } catch (FileAlreadyExistsException ignored) { } appClassLoader = new PathClassLoader(cacheApkPath, aInfo.nativeLibraryDir, baseClassLoader.getParent()); - if (originalAppComponentFactoryClass == null || originalAppComponentFactoryClass.isEmpty()) - originalAppComponentFactory = new AppComponentFactory(); - else + + try { originalAppComponentFactory = (AppComponentFactory) appClassLoader.loadClass(originalAppComponentFactoryClass).newInstance(); + } catch (ClassNotFoundException | NullPointerException ignored) { + if (originalAppComponentFactoryClass != null && !originalAppComponentFactoryClass.isEmpty()) + Log.w(TAG, "Original AppComponentFactory not found"); + originalAppComponentFactory = new AppComponentFactory(); + } + Log.d(TAG, "Instantiate original AppComponentFactory: " + originalAppComponentFactory); } catch (Throwable e) { Log.e(TAG, "initOriginalAppComponentFactory", e); @@ -59,6 +64,9 @@ public class LSPAppComponentFactoryStub extends AppComponentFactory { @Override public ClassLoader instantiateClassLoader(ClassLoader cl, ApplicationInfo aInfo) { baseClassLoader = cl; + var apkPath = baseClassLoader.getResource("AndroidManifest.xml").getPath(); + apkPath = apkPath.substring(5, apkPath.lastIndexOf('!')); + lspClassLoader = new PathClassLoader(apkPath, null, null); initOriginalAppComponentFactory(aInfo); Log.d(TAG, "baseClassLoader is " + baseClassLoader); Log.d(TAG, "appClassLoader is " + appClassLoader); @@ -67,7 +75,7 @@ public class LSPAppComponentFactoryStub extends AppComponentFactory { @Override public Application instantiateApplication(ClassLoader cl, String className) throws IllegalAccessException, InstantiationException, ClassNotFoundException { - baseClassLoader.loadClass(PROXY_APPLICATION).newInstance(); + lspClassLoader.loadClass(PROXY_APPLICATION).newInstance(); return originalAppComponentFactory.instantiateApplication(cl, className); } diff --git a/appstub/src/main/java/org/lsposed/lspatch/appstub/LSPApplicationStub.java b/appstub/src/main/java/org/lsposed/lspatch/appstub/LSPApplicationStub.java index a3b4e9c..468009c 100644 --- a/appstub/src/main/java/org/lsposed/lspatch/appstub/LSPApplicationStub.java +++ b/appstub/src/main/java/org/lsposed/lspatch/appstub/LSPApplicationStub.java @@ -1,10 +1,15 @@ package org.lsposed.lspatch.appstub; +import android.annotation.SuppressLint; import android.app.Application; import android.content.Context; +import android.util.Log; +import java.io.BufferedReader; import java.io.ByteArrayOutputStream; +import java.io.InputStreamReader; +@SuppressLint("UnsafeDynamicallyLoadedCode") public class LSPApplicationStub extends Application { private static byte[] dex = null; @@ -19,9 +24,16 @@ public class LSPApplicationStub extends Application { } dex = os.toByteArray(); } catch (Throwable e) { - android.util.Log.e("LSPatch", "load dex error", e); + Log.e("LSPatch", "load dex error", e); + } + + try (var br = new BufferedReader(new InputStreamReader(Runtime.getRuntime().exec("getprop ro.product.cpu.abi").getInputStream()))) { + String arch = br.readLine(); + String path = LSPApplicationStub.class.getClassLoader().getResource("assets/lib/" + arch + "/liblspd.so").getPath().substring(5); + System.load(path); + } catch (Throwable e) { + Log.e("LSPatch", "load lspd error", e); } - System.loadLibrary("lspd"); } @Override diff --git a/patch/src/main/java/org/lsposed/patch/LSPatch.java b/patch/src/main/java/org/lsposed/patch/LSPatch.java index 7bec3c7..2d84aa0 100644 --- a/patch/src/main/java/org/lsposed/patch/LSPatch.java +++ b/patch/src/main/java/org/lsposed/patch/LSPatch.java @@ -32,7 +32,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; -import java.util.Set; import java.util.jar.JarFile; public class LSPatch { @@ -97,6 +96,12 @@ public class LSPatch { "x86_64" )); + private static final ZFileOptions Z_FILE_OPTIONS = new ZFileOptions().setAlignmentRule(AlignmentRules.compose( + AlignmentRules.constantForSuffix(".so", 4096), + AlignmentRules.constantForSuffix(RESOURCES_ARSC, 4), + AlignmentRules.constantForSuffix(ORIGINAL_APK_ASSET_PATH, 4096) + )); + private static JCommander jCommander; public static void main(String... args) throws IOException { @@ -154,14 +159,7 @@ public class LSPatch { System.out.println("Parsing original apk..."); - final ZFileOptions zFileOptions = new ZFileOptions(); - - final var alignmentRule = AlignmentRules.compose( - AlignmentRules.constantForSuffix(RESOURCES_ARSC, 4), - AlignmentRules.constantForSuffix(ORIGINAL_APK_ASSET_PATH, 4096) - ); - zFileOptions.setAlignmentRule(alignmentRule); - try (ZFile zFile = ZFile.openReadWrite(tmpApk, zFileOptions)) { + try (ZFile zFile = ZFile.openReadWrite(tmpApk, Z_FILE_OPTIONS)) { // copy origin apk to assets zFile.add(ORIGINAL_APK_ASSET_PATH, new FileInputStream(srcApkFile), false); @@ -225,36 +223,13 @@ public class LSPatch { throw new PatchError("Error when saving application name: " + e); } - // copy so and dex files into the unzipped apk - Set apkArchs = new HashSet<>(); - - if (verbose) - System.out.println("Search target apk library arch.."); - for (StoredEntry storedEntry : zFile.entries()) { - var name = storedEntry.getCentralDirectoryHeader().getName(); - if (name.startsWith("lib/") && name.length() >= 5) { - var arch = name.substring(4, name.indexOf('/', 5)); - apkArchs.add(arch); - } - } - - if (apkArchs.isEmpty()) { - apkArchs.addAll(APK_LIB_PATH_ARRAY); - } - - apkArchs.removeIf((arch) -> { - if (!APK_LIB_PATH_ARRAY.contains(arch) && !arch.equals("armeabi")) { - System.err.println("Warning: unsupported arch " + arch + ". Skipping..."); - return true; - } - return false; - }); if (verbose) System.out.println("Adding native lib.."); - for (String arch : apkArchs) { - // lib/armeabi-v7a -> armeabi-v7a - String entryName = "lib/" + arch + "/liblspd.so"; + // copy so and dex files into the unzipped apk + // do not put liblspd.so into apk!lib because x86 native bridge causes crash + for (String arch : APK_LIB_PATH_ARRAY) { + String entryName = "assets/lib/" + arch + "/liblspd.so"; try (var is = getClass().getClassLoader().getResourceAsStream("assets/so/" + (arch.equals("armeabi") ? "armeabi-v7a" : arch) + "/liblspd.so")) { zFile.add(entryName, is, false); // no compress for so } catch (Throwable e) {