From 3b74b255ffda19e54268032bcd66b1a98f387c1d Mon Sep 17 00:00:00 2001 From: Nikolay Nesterov Date: Fri, 28 Dec 2018 17:05:40 +0300 Subject: [PATCH 1/3] Add support for splitted apk --- java/com/facebook/soloader/ApkSoSource.java | 4 +- java/com/facebook/soloader/SoLoader.java | 44 +++++++++++++++------ 2 files changed, 35 insertions(+), 13 deletions(-) diff --git a/java/com/facebook/soloader/ApkSoSource.java b/java/com/facebook/soloader/ApkSoSource.java index 5067398..f6463c8 100644 --- a/java/com/facebook/soloader/ApkSoSource.java +++ b/java/com/facebook/soloader/ApkSoSource.java @@ -46,11 +46,11 @@ public class ApkSoSource extends ExtractFromZipSoSource { private final int mFlags; - public ApkSoSource(Context context, String name, int flags) { + public ApkSoSource(Context context, String apkPath, String name, int flags) { super( context, name, - new File(context.getApplicationInfo().sourceDir), + new File(apkPath), // The regular expression matches libraries that would ordinarily be unpacked // during installation. "^lib/([^/]+)/([^/]+\\.so)$"); diff --git a/java/com/facebook/soloader/SoLoader.java b/java/com/facebook/soloader/SoLoader.java index 2da2af8..4b4bfe8 100644 --- a/java/com/facebook/soloader/SoLoader.java +++ b/java/com/facebook/soloader/SoLoader.java @@ -91,10 +91,10 @@ public class SoLoader { private static int sSoSourcesVersion = 0; - /** A backup SoSource to try if a lib file is corrupted */ + /** A backup SoSources to try if a lib file is corrupted */ @GuardedBy("sSoSourcesLock") @Nullable - private static UnpackingSoSource sBackupSoSource; + private static UnpackingSoSource[] sBackupSoSources; /** * A SoSource for the Context.ApplicationInfo.nativeLibsDir that can be updated if the application @@ -121,9 +121,12 @@ public class SoLoader { /** Wrapper for System.loadLlibrary. */ @Nullable private static SystemLoadLibraryWrapper sSystemLoadLibraryWrapper = null; - /** Name of the directory we use for extracted DSOs from built-in SO sources (APK, exopackage) */ + /** Name of the directory we use for extracted DSOs from built-in SO sources (main APK, exopackage) */ private static final String SO_STORE_NAME_MAIN = "lib-main"; + /** Name of the directory we use for extracted DSOs from splitted apks */ + private static final String SO_STORE_NAME_SPLITTED = "lib-"; + /** Enable the exopackage SoSource. */ public static final int SOLOADER_ENABLE_EXOPACKAGE = (1 << 0); @@ -230,7 +233,7 @@ private static void initSoSources(Context context, int flags, @Nullable SoFileLo // if ((flags & SOLOADER_ENABLE_EXOPACKAGE) != 0) { - sBackupSoSource = null; + sBackupSoSources = null; Log.d(TAG, "adding exo package source: " + SO_STORE_NAME_MAIN); soSources.add(0, new ExoSoSource(context, SO_STORE_NAME_MAIN)); } else { @@ -260,11 +263,24 @@ private static void initSoSources(Context context, int flags, @Nullable SoFileLo } if ((sFlags & SOLOADER_DISABLE_BACKUP_SOSOURCE) != 0) { - sBackupSoSource = null; + sBackupSoSources = null; } else { - sBackupSoSource = new ApkSoSource(context, SO_STORE_NAME_MAIN, apkSoSourceFlags); - Log.d(TAG, "adding backup source: " + sBackupSoSource.toString()); - soSources.add(0, sBackupSoSource); + + String mainApkDir = context.getApplicationInfo().sourceDir; + ArrayList backupSources = new ArrayList<>(); + ApkSoSource mainApkSource = new ApkSoSource(context, mainApkDir, SO_STORE_NAME_MAIN, apkSoSourceFlags); + backupSources.add(mainApkSource); + Log.d(TAG, "adding backup source: " + mainApkSource.toString()); + + int splitIndex = 0; + for (String splitApkDir: context.getApplicationInfo().splitSourceDirs) { + ApkSoSource splittedApkSource = new ApkSoSource(context, splitApkDir, SO_STORE_NAME_SPLITTED + (splitIndex++), apkSoSourceFlags); + Log.d(TAG, "adding backup source: " + mainApkSource.toString()); + backupSources.add(splittedApkSource); + } + + sBackupSoSources = backupSources.toArray(new UnpackingSoSource[backupSources.size()]); + soSources.addAll(0, backupSources); } } } @@ -647,11 +663,17 @@ private static void doLoadLibraryBySoName( for (int i = 0; result == SoSource.LOAD_RESULT_NOT_FOUND && i < sSoSources.length; ++i) { SoSource currentSource = sSoSources[i]; result = currentSource.loadLibrary(soName, loadFlags, oldPolicy); - if (result == SoSource.LOAD_RESULT_CORRUPTED_LIB_FILE && sBackupSoSource != null) { + if (result == SoSource.LOAD_RESULT_CORRUPTED_LIB_FILE && sBackupSoSources != null) { // Let's try from the backup source Log.d(TAG, "Trying backup SoSource for " + soName); - sBackupSoSource.prepare(soName); - result = sBackupSoSource.loadLibrary(soName, loadFlags, oldPolicy); + for (UnpackingSoSource backupSoSource: sBackupSoSources) { + backupSoSource.prepare(soName); + int resultFromBackup = backupSoSource.loadLibrary(soName, loadFlags, oldPolicy); + if (resultFromBackup == SoSource.LOAD_RESULT_LOADED) { + result = resultFromBackup; + break; + } + } break; } } From 3d9fe84e119493534cd846e0cb6d8a50429197d0 Mon Sep 17 00:00:00 2001 From: Nikolay Nesterov Date: Wed, 9 Jan 2019 21:45:37 +0300 Subject: [PATCH 2/3] Fix crash on pre-lollipop devices. (The don't support splits) --- java/com/facebook/soloader/SoLoader.java | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/java/com/facebook/soloader/SoLoader.java b/java/com/facebook/soloader/SoLoader.java index 4b4bfe8..c1f2882 100644 --- a/java/com/facebook/soloader/SoLoader.java +++ b/java/com/facebook/soloader/SoLoader.java @@ -270,13 +270,16 @@ private static void initSoSources(Context context, int flags, @Nullable SoFileLo ArrayList backupSources = new ArrayList<>(); ApkSoSource mainApkSource = new ApkSoSource(context, mainApkDir, SO_STORE_NAME_MAIN, apkSoSourceFlags); backupSources.add(mainApkSource); - Log.d(TAG, "adding backup source: " + mainApkSource.toString()); - - int splitIndex = 0; - for (String splitApkDir: context.getApplicationInfo().splitSourceDirs) { - ApkSoSource splittedApkSource = new ApkSoSource(context, splitApkDir, SO_STORE_NAME_SPLITTED + (splitIndex++), apkSoSourceFlags); - Log.d(TAG, "adding backup source: " + mainApkSource.toString()); - backupSources.add(splittedApkSource); + Log.d(TAG, "adding backup source from : " + mainApkSource.toString()); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + Log.d(TAG, "adding backup sources from split apks"); + int splitIndex = 0; + for (String splitApkDir : context.getApplicationInfo().splitSourceDirs) { + ApkSoSource splittedApkSource = new ApkSoSource(context, splitApkDir, SO_STORE_NAME_SPLITTED + (splitIndex++), apkSoSourceFlags); + Log.d(TAG, "adding backup source: " + splittedApkSource.toString()); + backupSources.add(splittedApkSource); + } } sBackupSoSources = backupSources.toArray(new UnpackingSoSource[backupSources.size()]); From 1a044bdfb739c27ff464087e2518482cf1c4543a Mon Sep 17 00:00:00 2001 From: Nikolay Nesterov Date: Wed, 16 Jan 2019 16:16:51 +0300 Subject: [PATCH 3/3] Add null-check for splitSourceDirs --- java/com/facebook/soloader/SoLoader.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/com/facebook/soloader/SoLoader.java b/java/com/facebook/soloader/SoLoader.java index c1f2882..29beb7a 100644 --- a/java/com/facebook/soloader/SoLoader.java +++ b/java/com/facebook/soloader/SoLoader.java @@ -272,7 +272,7 @@ private static void initSoSources(Context context, int flags, @Nullable SoFileLo backupSources.add(mainApkSource); Log.d(TAG, "adding backup source from : " + mainApkSource.toString()); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && context.getApplicationInfo().splitSourceDirs != null) { Log.d(TAG, "adding backup sources from split apks"); int splitIndex = 0; for (String splitApkDir : context.getApplicationInfo().splitSourceDirs) {