diff --git a/java/com/facebook/soloader/BackupSoSource.java b/java/com/facebook/soloader/BackupSoSource.java index 60ec346..84d2472 100644 --- a/java/com/facebook/soloader/BackupSoSource.java +++ b/java/com/facebook/soloader/BackupSoSource.java @@ -103,7 +103,28 @@ public void prepare(int flags) throws IOException { mInitialized = true; } + public boolean peekAndPrepareSoSource(String soName, int prepareFlags) throws IOException { + boolean found = false; + try (Unpacker u = makeUnpacker()) { + Dso[] dsos = u.getDsos(); + for (Dso dso : dsos) { + if (dso.name.equals(soName)) { + LogUtil.e(SoLoader.TAG, "Found " + soName + " in " + getName()); + found = true; + break; + } + } + } + if (!found) { + return false; + } + LogUtil.e(SoLoader.TAG, "Preparing " + getName()); + prepare(prepareFlags); + return true; + } + protected class ApkUnpacker extends Unpacker { + @Override public Dso[] getDsos() throws IOException { ArrayList dsos = new ArrayList<>(); diff --git a/java/com/facebook/soloader/recovery/ReunpackBackupSoSources.java b/java/com/facebook/soloader/recovery/ReunpackBackupSoSources.java index b9d46d9..3dbcea4 100644 --- a/java/com/facebook/soloader/recovery/ReunpackBackupSoSources.java +++ b/java/com/facebook/soloader/recovery/ReunpackBackupSoSources.java @@ -22,6 +22,7 @@ import com.facebook.soloader.SoLoaderDSONotFoundError; import com.facebook.soloader.SoLoaderULError; import com.facebook.soloader.SoSource; +import java.io.IOException; /** * RecoveryStrategy that detects cases when SoLoader failed to load a corrupted library, case in @@ -38,26 +39,50 @@ public boolean recover(UnsatisfiedLinkError error, SoSource[] soSources) { // Only recover from SoLoaderULE errors return false; } + SoLoaderULError err = (SoLoaderULError) error; + String soName = err.getSoName(); + String message = err.getMessage(); - if (error instanceof SoLoaderDSONotFoundError) { - // Do not attempt to recover if DSO is not found + if (soName == null) { + LogUtil.e(SoLoader.TAG, "No so name provided in ULE, cannot recover"); return false; } - SoLoaderULError err = (SoLoaderULError) error; - String message = err.getMessage(); - if (message == null || (!message.contains("/app/") && !message.contains("/mnt/"))) { - // Do not attempt to recovery if the DSO wasn't in the data/app directory + if (err instanceof SoLoaderDSONotFoundError) { + // Recover if DSO is not found + logRecovery(err, soName); + + return recoverDSONotFoundError(soSources, soName, 0); + } else if (message == null || (!message.contains("/app/") && !message.contains("/mnt/"))) { + // Don't recover if the DSO wasn't in the data/app directory + return false; + } else { + logRecovery(err, soName); + return lazyPrepareBackupSoSource(soSources, soName); } + } - String soName = err.getSoName(); - LogUtil.e( - SoLoader.TAG, - "Reunpacking BackupSoSources due to " - + error - + ((soName == null) ? "" : (", retrying for specific library " + soName))); + private boolean recoverDSONotFoundError(SoSource[] soSources, String soName, int prepareFlags) { + try { + for (SoSource soSource : soSources) { + if (!(soSource instanceof BackupSoSource)) { + continue; + } + BackupSoSource uss = (BackupSoSource) soSource; + if (uss.peekAndPrepareSoSource(soName, prepareFlags)) { + return true; + } + } + return false; + } catch (IOException ioException) { + LogUtil.e(SoLoader.TAG, "Failed to run recovery for backup so source due to: " + ioException); + return false; + } + } + + private boolean lazyPrepareBackupSoSource(SoSource[] soSources, String soName) { for (SoSource soSource : soSources) { if (!(soSource instanceof BackupSoSource)) { // NonApk SoSources get reunpacked in ReunpackNonBackupSoSource recovery strategy @@ -88,4 +113,13 @@ public boolean recover(UnsatisfiedLinkError error, SoSource[] soSources) { return false; } + + private void logRecovery(Error error, String soName) { + LogUtil.e( + SoLoader.TAG, + "Reunpacking BackupSoSources due to " + + error + + ", retrying for specific library " + + soName); + } }