1616
1717package com .facebook .soloader ;
1818
19+ import android .content .res .AssetFileDescriptor ;
1920import java .io .File ;
21+ import java .io .FileNotFoundException ;
2022import java .io .IOException ;
23+ import java .io .InputStream ;
24+ import java .util .zip .ZipEntry ;
25+ import java .util .zip .ZipFile ;
2126
2227/**
2328 * Represents an APK split that contains native libraries. There are two kinds:
3035 */
3136public abstract class Split {
3237
38+ /** An InputStream that closes an associated ZipFile when the stream is closed. */
39+ private static class ZipEntryInputStream extends InputStream {
40+ private final InputStream mDelegate ;
41+ private final ZipFile mZipFile ;
42+
43+ ZipEntryInputStream (InputStream delegate , ZipFile zipFile ) {
44+ mDelegate = delegate ;
45+ mZipFile = zipFile ;
46+ }
47+
48+ @ Override
49+ public int read () throws IOException {
50+ return mDelegate .read ();
51+ }
52+
53+ @ Override
54+ public int read (byte [] b , int off , int len ) throws IOException {
55+ return mDelegate .read (b , off , len );
56+ }
57+
58+ @ Override
59+ public int available () throws IOException {
60+ return mDelegate .available ();
61+ }
62+
63+ @ Override
64+ public void close () throws IOException {
65+ try {
66+ mDelegate .close ();
67+ } finally {
68+ mZipFile .close ();
69+ }
70+ }
71+ }
72+
3373 /** Returns the file system path to the split APK. */
3474 public abstract String getPath ();
3575
@@ -48,6 +88,34 @@ public String getLibraryDirectory(String abi) {
4888 return getEntryPath ("lib/" + abi + "/" );
4989 }
5090
91+ /**
92+ * Opens a library from this split and returns an {@link InputStream} to read its contents. The
93+ * library is looked up under {@code lib/<abi>/<soName>} inside the archive. Uses the primary ABI.
94+ */
95+ public InputStream openLib (String soName ) throws IOException {
96+ return openLib (SoLoader .getPrimaryAbi (), soName );
97+ }
98+
99+ /**
100+ * Opens a library from this split and returns an {@link InputStream} to read its contents. The
101+ * library is looked up under {@code lib/<abi>/<soName>} inside the archive.
102+ */
103+ public InputStream openLib (String abi , String soName ) throws IOException {
104+ ZipFile zipFile = new ZipFile (getPath ());
105+ String entryName = "lib/" + abi + "/" + soName ;
106+ ZipEntry entry = zipFile .getEntry (entryName );
107+ if (entry == null ) {
108+ zipFile .close ();
109+ throw new FileNotFoundException ("Entry not found: " + entryName + " in " + getPath ());
110+ }
111+ InputStream is = zipFile .getInputStream (entry );
112+ if (is == null ) {
113+ zipFile .close ();
114+ throw new IOException ("Failed to open entry: " + entryName + " in " + getPath ());
115+ }
116+ return new ZipEntryInputStream (is , zipFile );
117+ }
118+
51119 /** Finds the installed ABI split for the given feature. */
52120 public static Installed findAbiSplit (String feature ) {
53121 return new Installed (Splits .findAbiSplit (feature ));
@@ -82,6 +150,22 @@ public String getPath() {
82150 return Splits .getSplitPath (mSplitName );
83151 }
84152
153+ private boolean isBaseFeature () {
154+ return "base.apk" .equals (mSplitName ) || mSplitName .startsWith ("split_config." );
155+ }
156+
157+ @ Override
158+ public InputStream openLib (String abi , String soName ) throws IOException {
159+ if (isBaseFeature ()) {
160+ AssetFileDescriptor afd =
161+ SoLoader .getApplicationContext ()
162+ .getAssets ()
163+ .openNonAssetFd ("lib/" + abi + "/" + soName );
164+ return afd .createInputStream ();
165+ }
166+ return super .openLib (abi , soName );
167+ }
168+
85169 @ Override
86170 public String toString () {
87171 return "installed split:" + mSplitName ;
0 commit comments