diff --git a/java/com/facebook/soloader/ApkSoSource.java b/java/com/facebook/soloader/ApkSoSource.java index 1fa4596..9e8fc88 100644 --- a/java/com/facebook/soloader/ApkSoSource.java +++ b/java/com/facebook/soloader/ApkSoSource.java @@ -72,15 +72,40 @@ protected class ApkUnpacker extends ZipUnpacker { } @Override - protected boolean shouldExtract(ZipEntry ze, String soName) { + protected ZipDso[] getExtractableDsosFromZip() { + if (mDsos != null) { + return mDsos; + } + + ZipDso[] dsos = computeDsosFromZip(); + for (ZipDso zd : dsos) { + if (shouldExtract(zd.backingEntry, zd.name)) { + // If one library is corrupted, extract all of them to simplify the logic of computing + // dependencies. By default, the application so source (/data/app) relies on the bionic + // linker to resolve dependencies. + // If there's 2 /data/app libraries with the same corrupted depdendency, we might end up + // facing multiple load failures that can be avoided: + // A depends on C + // B depends on C + // C is corrupted + // Try to load A (from app so source - data/app) -> load C first (from /data/app) -> C + // fails, hence unpack A and C to /data/data + // Try to load B (from app so source - data/app) -> load C first (from /data/app) -> + // fail to load, even though C has previously been unpacked to /data/data and can be used + mDsos = dsos; + return mDsos; + } + } + mDsos = new ZipDso[0]; + return mDsos; + } + + private boolean shouldExtract(ZipEntry ze, String soName) { StringBuilder msg = new StringBuilder(); boolean shouldExtract = false; String zipPath = ze.getName(); - if (soName.equals(mCorruptedLib)) { - mCorruptedLib = null; - msg.append("allowing consideration of corrupted lib ").append(soName); - shouldExtract = true; - } else if ((mFlags & PREFER_ANDROID_LIBS_DIRECTORY) == 0) { + + if ((mFlags & PREFER_ANDROID_LIBS_DIRECTORY) == 0) { msg.append("allowing consideration of ") .append(zipPath) .append(": self-extraction preferred"); diff --git a/java/com/facebook/soloader/ExtractFromZipSoSource.java b/java/com/facebook/soloader/ExtractFromZipSoSource.java index 93682f4..0d2dc29 100644 --- a/java/com/facebook/soloader/ExtractFromZipSoSource.java +++ b/java/com/facebook/soloader/ExtractFromZipSoSource.java @@ -61,7 +61,7 @@ protected Unpacker makeUnpacker() throws IOException { protected class ZipUnpacker extends Unpacker { - private @Nullable ZipDso[] mDsos; + protected @Nullable ZipDso[] mDsos; private final ZipFile mZipFile; private final UnpackingSoSource mSoSource; @@ -70,16 +70,7 @@ protected class ZipUnpacker extends Unpacker { mSoSource = soSource; } - /** - * If the list of zip DSOs is not created, generate that by iterating through all zip entries - * and doing pattern matching against a zipped libs pattern. - * - * @return mDsos - */ - final ZipDso[] ensureDsosInitialised() { - if (mDsos != null) { - return mDsos; - } + ZipDso[] computeDsosFromZip() { LinkedHashSet librariesAbiSet = new LinkedHashSet<>(); HashMap providedLibraries = new HashMap<>(); Pattern zipSearchPattern = Pattern.compile(mZipSearchPattern); @@ -108,36 +99,22 @@ final ZipDso[] ensureDsosInitialised() { ZipDso[] dsos = providedLibraries.values().toArray(new ZipDso[providedLibraries.size()]); Arrays.sort(dsos); - int nrFilteredDsos = 0; - for (int i = 0; i < dsos.length; ++i) { - ZipDso zd = dsos[i]; - if (shouldExtract(zd.backingEntry, zd.name)) { - nrFilteredDsos += 1; - } else { - dsos[i] = null; - } - } - ZipDso[] filteredDsos = new ZipDso[nrFilteredDsos]; - for (int i = 0, j = 0; i < dsos.length; ++i) { - ZipDso zd = dsos[i]; - if (zd == null) { - continue; - } - filteredDsos[j++] = zd; - } - mDsos = filteredDsos; - return mDsos; + return dsos; } /** - * Hook for subclasses to filter out certain library names from being extracted from the zip - * file. + * If the list of zip DSOs is not created, generate that by iterating through all zip entries + * and doing pattern matching against a zipped libs pattern. * - * @param soName Candidate soName - * @param ze Zip entry for file to extract + * @return mDsos */ - protected boolean shouldExtract(ZipEntry ze, String soName) { - return true; + ZipDso[] getExtractableDsosFromZip() { + if (mDsos != null) { + return mDsos; + } + + mDsos = computeDsosFromZip(); + return mDsos; } @Override @@ -147,7 +124,7 @@ public void close() throws IOException { @Override public final Dso[] getDsos() throws IOException { - return ensureDsosInitialised(); + return getExtractableDsosFromZip(); } @Override @@ -161,13 +138,13 @@ private final class ZipBackedInputDsoIterator extends InputDsoIterator { @Override public boolean hasNext() { - ensureDsosInitialised(); + getExtractableDsosFromZip(); return mCurrentDso < mDsos.length; } @Override public InputDso next() throws IOException { - ensureDsosInitialised(); + getExtractableDsosFromZip(); ZipDso zipDso = mDsos[mCurrentDso++]; InputStream is = mZipFile.getInputStream(zipDso.backingEntry); try { @@ -199,7 +176,7 @@ protected String computeFileHash(File file) { } } - private static final class ZipDso extends Dso implements Comparable { + protected static final class ZipDso extends Dso implements Comparable { final ZipEntry backingEntry; final int abiScore; diff --git a/java/com/facebook/soloader/UnpackingSoSource.java b/java/com/facebook/soloader/UnpackingSoSource.java index d922aba..64c9fff 100644 --- a/java/com/facebook/soloader/UnpackingSoSource.java +++ b/java/com/facebook/soloader/UnpackingSoSource.java @@ -56,7 +56,6 @@ public abstract class UnpackingSoSource extends DirectorySoSource implements Asy private static final byte STATE_CLEAN = 1; protected final Context mContext; - @Nullable protected String mCorruptedLib; @Nullable private String[] mAbis; @@ -538,12 +537,6 @@ public String getLibraryPath(String soName) throws IOException { return soFile.getCanonicalPath(); } - /** Prepare this SoSource extracting a corrupted library. */ - public void prepare(String soName) throws IOException { - mCorruptedLib = soName; - prepareForceRefresh(); - } - /** Prepare this SoSource by force extracting a corrupted library. */ public void prepareForceRefresh() throws IOException { prepare(SoSource.PREPARE_FLAG_FORCE_REFRESH); diff --git a/java/com/facebook/soloader/recovery/ReunpackSoSources.java b/java/com/facebook/soloader/recovery/ReunpackSoSources.java index f343d13..e8b44c3 100644 --- a/java/com/facebook/soloader/recovery/ReunpackSoSources.java +++ b/java/com/facebook/soloader/recovery/ReunpackSoSources.java @@ -68,7 +68,7 @@ public boolean recover(UnsatisfiedLinkError error, SoSource[] soSources) { LogUtil.e(SoLoader.TAG, "Runpacking ApkSoSource " + uss.getClass().getName()); try { // Re-unpack the ApkSoSource libraries first - uss.prepare(soName); + uss.prepareForceRefresh(); } catch (Exception e) { // Catch a general error and log it, rather than failing during recovery and crashing the // app @@ -88,7 +88,7 @@ public boolean recover(UnsatisfiedLinkError error, SoSource[] soSources) { LogUtil.e(SoLoader.TAG, "Runpacking " + uss.getClass().getName()); try { // Re-unpack from other UnpackingSoSources as well - uss.prepare(soName); + uss.prepareForceRefresh(); } catch (Exception e) { // Catch a general error and log it, rather than failing during recovery and crashing the // app