Initial commit
This commit is contained in:
399
sources/androidx/multidex/MultiDex.java
Normal file
399
sources/androidx/multidex/MultiDex.java
Normal file
@@ -0,0 +1,399 @@
|
||||
package androidx.multidex;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
import com.liulishuo.filedownloader.model.FileDownloadModel;
|
||||
import dalvik.system.DexFile;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
/* loaded from: classes.dex */
|
||||
public final class MultiDex {
|
||||
private static final Set<File> a = new HashSet();
|
||||
private static final boolean b = a(System.getProperty("java.vm.version"));
|
||||
|
||||
private static final class V4 {
|
||||
static void a(ClassLoader classLoader, List<? extends File> list) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, IOException {
|
||||
int size = list.size();
|
||||
Field b = MultiDex.b(classLoader, FileDownloadModel.PATH);
|
||||
StringBuilder sb = new StringBuilder((String) b.get(classLoader));
|
||||
String[] strArr = new String[size];
|
||||
File[] fileArr = new File[size];
|
||||
ZipFile[] zipFileArr = new ZipFile[size];
|
||||
DexFile[] dexFileArr = new DexFile[size];
|
||||
ListIterator<? extends File> listIterator = list.listIterator();
|
||||
while (listIterator.hasNext()) {
|
||||
File next = listIterator.next();
|
||||
String absolutePath = next.getAbsolutePath();
|
||||
sb.append(':');
|
||||
sb.append(absolutePath);
|
||||
int previousIndex = listIterator.previousIndex();
|
||||
strArr[previousIndex] = absolutePath;
|
||||
fileArr[previousIndex] = next;
|
||||
zipFileArr[previousIndex] = new ZipFile(next);
|
||||
dexFileArr[previousIndex] = DexFile.loadDex(absolutePath, absolutePath + ".dex", 0);
|
||||
}
|
||||
b.set(classLoader, sb.toString());
|
||||
MultiDex.b(classLoader, "mPaths", strArr);
|
||||
MultiDex.b(classLoader, "mFiles", fileArr);
|
||||
MultiDex.b(classLoader, "mZips", zipFileArr);
|
||||
MultiDex.b(classLoader, "mDexs", dexFileArr);
|
||||
}
|
||||
}
|
||||
|
||||
private static ApplicationInfo b(Context context) {
|
||||
try {
|
||||
return context.getApplicationInfo();
|
||||
} catch (RuntimeException e) {
|
||||
Log.w("MultiDex", "Failure while trying to obtain ApplicationInfo from Context. Must be running in test mode. Skip patching.", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static void c(Context context) {
|
||||
Log.i("MultiDex", "Installing application");
|
||||
if (b) {
|
||||
Log.i("MultiDex", "VM has multidex support, MultiDex support library is disabled.");
|
||||
return;
|
||||
}
|
||||
if (Build.VERSION.SDK_INT < 4) {
|
||||
throw new RuntimeException("MultiDex installation failed. SDK " + Build.VERSION.SDK_INT + " is unsupported. Min SDK version is 4.");
|
||||
}
|
||||
try {
|
||||
ApplicationInfo b2 = b(context);
|
||||
if (b2 == null) {
|
||||
Log.i("MultiDex", "No ApplicationInfo available, i.e. running on a test Context: MultiDex support library is disabled.");
|
||||
} else {
|
||||
a(context, new File(b2.sourceDir), new File(b2.dataDir), "secondary-dexes", "", true);
|
||||
Log.i("MultiDex", "install done");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e("MultiDex", "MultiDex installation failure", e);
|
||||
throw new RuntimeException("MultiDex installation failed (" + e.getMessage() + ").");
|
||||
}
|
||||
}
|
||||
|
||||
/* JADX INFO: Access modifiers changed from: private */
|
||||
public static Field b(Object obj, String str) throws NoSuchFieldException {
|
||||
for (Class<?> cls = obj.getClass(); cls != null; cls = cls.getSuperclass()) {
|
||||
try {
|
||||
Field declaredField = cls.getDeclaredField(str);
|
||||
if (!declaredField.isAccessible()) {
|
||||
declaredField.setAccessible(true);
|
||||
}
|
||||
return declaredField;
|
||||
} catch (NoSuchFieldException unused) {
|
||||
}
|
||||
}
|
||||
throw new NoSuchFieldException("Field " + str + " not found in " + obj.getClass());
|
||||
}
|
||||
|
||||
private static void a(Context context, File file, File file2, String str, String str2, boolean z) throws IOException, IllegalArgumentException, IllegalAccessException, NoSuchFieldException, InvocationTargetException, NoSuchMethodException, SecurityException, ClassNotFoundException, InstantiationException {
|
||||
synchronized (a) {
|
||||
if (a.contains(file)) {
|
||||
return;
|
||||
}
|
||||
a.add(file);
|
||||
if (Build.VERSION.SDK_INT > 20) {
|
||||
Log.w("MultiDex", "MultiDex is not guaranteed to work in SDK version " + Build.VERSION.SDK_INT + ": SDK version higher than 20 should be backed by runtime with built-in multidex capabilty but it's not the case here: java.vm.version=\"" + System.getProperty("java.vm.version") + "\"");
|
||||
}
|
||||
try {
|
||||
ClassLoader classLoader = context.getClassLoader();
|
||||
if (classLoader == null) {
|
||||
Log.e("MultiDex", "Context class loader is null. Must be running in test mode. Skip patching.");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
a(context);
|
||||
} catch (Throwable th) {
|
||||
Log.w("MultiDex", "Something went wrong when trying to clear old MultiDex extraction, continuing without cleaning.", th);
|
||||
}
|
||||
File a2 = a(context, file2, str);
|
||||
MultiDexExtractor multiDexExtractor = new MultiDexExtractor(file, a2);
|
||||
IOException e = null;
|
||||
try {
|
||||
try {
|
||||
a(classLoader, a2, multiDexExtractor.a(context, str2, false));
|
||||
} catch (IOException e2) {
|
||||
if (z) {
|
||||
Log.w("MultiDex", "Failed to install extracted secondary dex files, retrying with forced extraction", e2);
|
||||
a(classLoader, a2, multiDexExtractor.a(context, str2, true));
|
||||
} else {
|
||||
throw e2;
|
||||
}
|
||||
}
|
||||
try {
|
||||
} catch (IOException e3) {
|
||||
e = e3;
|
||||
}
|
||||
if (e != null) {
|
||||
throw e;
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
multiDexExtractor.close();
|
||||
} catch (IOException unused) {
|
||||
}
|
||||
}
|
||||
} catch (RuntimeException e4) {
|
||||
Log.w("MultiDex", "Failure while trying to obtain Context class loader. Must be running in test mode. Skip patching.", e4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final class V14 {
|
||||
private static final int b = 4;
|
||||
private final ElementConstructor a;
|
||||
|
||||
private interface ElementConstructor {
|
||||
Object a(File file, DexFile dexFile) throws IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException, IOException;
|
||||
}
|
||||
|
||||
private static class ICSElementConstructor implements ElementConstructor {
|
||||
private final Constructor<?> a;
|
||||
|
||||
ICSElementConstructor(Class<?> cls) throws SecurityException, NoSuchMethodException {
|
||||
this.a = cls.getConstructor(File.class, ZipFile.class, DexFile.class);
|
||||
this.a.setAccessible(true);
|
||||
}
|
||||
|
||||
@Override // androidx.multidex.MultiDex.V14.ElementConstructor
|
||||
public Object a(File file, DexFile dexFile) throws IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException, IOException {
|
||||
return this.a.newInstance(file, new ZipFile(file), dexFile);
|
||||
}
|
||||
}
|
||||
|
||||
private static class JBMR11ElementConstructor implements ElementConstructor {
|
||||
private final Constructor<?> a;
|
||||
|
||||
JBMR11ElementConstructor(Class<?> cls) throws SecurityException, NoSuchMethodException {
|
||||
this.a = cls.getConstructor(File.class, File.class, DexFile.class);
|
||||
this.a.setAccessible(true);
|
||||
}
|
||||
|
||||
@Override // androidx.multidex.MultiDex.V14.ElementConstructor
|
||||
public Object a(File file, DexFile dexFile) throws IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException {
|
||||
return this.a.newInstance(file, file, dexFile);
|
||||
}
|
||||
}
|
||||
|
||||
private static class JBMR2ElementConstructor implements ElementConstructor {
|
||||
private final Constructor<?> a;
|
||||
|
||||
JBMR2ElementConstructor(Class<?> cls) throws SecurityException, NoSuchMethodException {
|
||||
this.a = cls.getConstructor(File.class, Boolean.TYPE, File.class, DexFile.class);
|
||||
this.a.setAccessible(true);
|
||||
}
|
||||
|
||||
@Override // androidx.multidex.MultiDex.V14.ElementConstructor
|
||||
public Object a(File file, DexFile dexFile) throws IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException {
|
||||
return this.a.newInstance(file, Boolean.FALSE, file, dexFile);
|
||||
}
|
||||
}
|
||||
|
||||
private V14() throws ClassNotFoundException, SecurityException, NoSuchMethodException {
|
||||
ElementConstructor jBMR2ElementConstructor;
|
||||
Class<?> cls = Class.forName("dalvik.system.DexPathList$Element");
|
||||
try {
|
||||
try {
|
||||
jBMR2ElementConstructor = new ICSElementConstructor(cls);
|
||||
} catch (NoSuchMethodException unused) {
|
||||
jBMR2ElementConstructor = new JBMR2ElementConstructor(cls);
|
||||
}
|
||||
} catch (NoSuchMethodException unused2) {
|
||||
jBMR2ElementConstructor = new JBMR11ElementConstructor(cls);
|
||||
}
|
||||
this.a = jBMR2ElementConstructor;
|
||||
}
|
||||
|
||||
static void a(ClassLoader classLoader, List<? extends File> list) throws IOException, SecurityException, IllegalArgumentException, ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchFieldException {
|
||||
Object obj = MultiDex.b(classLoader, "pathList").get(classLoader);
|
||||
Object[] a = new V14().a(list);
|
||||
try {
|
||||
MultiDex.b(obj, "dexElements", a);
|
||||
} catch (NoSuchFieldException e) {
|
||||
Log.w("MultiDex", "Failed find field 'dexElements' attempting 'pathElements'", e);
|
||||
MultiDex.b(obj, "pathElements", a);
|
||||
}
|
||||
}
|
||||
|
||||
private Object[] a(List<? extends File> list) throws IOException, SecurityException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException {
|
||||
Object[] objArr = new Object[list.size()];
|
||||
for (int i = 0; i < objArr.length; i++) {
|
||||
File file = list.get(i);
|
||||
objArr[i] = this.a.a(file, DexFile.loadDex(file.getPath(), a(file), 0));
|
||||
}
|
||||
return objArr;
|
||||
}
|
||||
|
||||
private static String a(File file) {
|
||||
File parentFile = file.getParentFile();
|
||||
String name = file.getName();
|
||||
return new File(parentFile, name.substring(0, name.length() - b) + ".dex").getPath();
|
||||
}
|
||||
}
|
||||
|
||||
/* JADX INFO: Access modifiers changed from: private */
|
||||
public static Method b(Object obj, String str, Class<?>... clsArr) throws NoSuchMethodException {
|
||||
for (Class<?> cls = obj.getClass(); cls != null; cls = cls.getSuperclass()) {
|
||||
try {
|
||||
Method declaredMethod = cls.getDeclaredMethod(str, clsArr);
|
||||
if (!declaredMethod.isAccessible()) {
|
||||
declaredMethod.setAccessible(true);
|
||||
}
|
||||
return declaredMethod;
|
||||
} catch (NoSuchMethodException unused) {
|
||||
}
|
||||
}
|
||||
throw new NoSuchMethodException("Method " + str + " with parameters " + Arrays.asList(clsArr) + " not found in " + obj.getClass());
|
||||
}
|
||||
|
||||
/* JADX INFO: Access modifiers changed from: private */
|
||||
public static void b(Object obj, String str, Object[] objArr) throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
|
||||
Field b2 = b(obj, str);
|
||||
Object[] objArr2 = (Object[]) b2.get(obj);
|
||||
Object[] objArr3 = (Object[]) Array.newInstance(objArr2.getClass().getComponentType(), objArr2.length + objArr.length);
|
||||
System.arraycopy(objArr2, 0, objArr3, 0, objArr2.length);
|
||||
System.arraycopy(objArr, 0, objArr3, objArr2.length, objArr.length);
|
||||
b2.set(obj, objArr3);
|
||||
}
|
||||
|
||||
private static final class V19 {
|
||||
static void a(ClassLoader classLoader, List<? extends File> list, File file) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, InvocationTargetException, NoSuchMethodException, IOException {
|
||||
IOException[] iOExceptionArr;
|
||||
Object obj = MultiDex.b(classLoader, "pathList").get(classLoader);
|
||||
ArrayList arrayList = new ArrayList();
|
||||
MultiDex.b(obj, "dexElements", a(obj, new ArrayList(list), file, arrayList));
|
||||
if (arrayList.size() > 0) {
|
||||
Iterator it = arrayList.iterator();
|
||||
while (it.hasNext()) {
|
||||
Log.w("MultiDex", "Exception in makeDexElement", (IOException) it.next());
|
||||
}
|
||||
Field b = MultiDex.b(obj, "dexElementsSuppressedExceptions");
|
||||
IOException[] iOExceptionArr2 = (IOException[]) b.get(obj);
|
||||
if (iOExceptionArr2 == null) {
|
||||
iOExceptionArr = (IOException[]) arrayList.toArray(new IOException[arrayList.size()]);
|
||||
} else {
|
||||
IOException[] iOExceptionArr3 = new IOException[arrayList.size() + iOExceptionArr2.length];
|
||||
arrayList.toArray(iOExceptionArr3);
|
||||
System.arraycopy(iOExceptionArr2, 0, iOExceptionArr3, arrayList.size(), iOExceptionArr2.length);
|
||||
iOExceptionArr = iOExceptionArr3;
|
||||
}
|
||||
b.set(obj, iOExceptionArr);
|
||||
IOException iOException = new IOException("I/O exception during makeDexElement");
|
||||
iOException.initCause((Throwable) arrayList.get(0));
|
||||
throw iOException;
|
||||
}
|
||||
}
|
||||
|
||||
private static Object[] a(Object obj, ArrayList<File> arrayList, File file, ArrayList<IOException> arrayList2) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
|
||||
return (Object[]) MultiDex.b(obj, "makeDexElements", (Class<?>[]) new Class[]{ArrayList.class, File.class, ArrayList.class}).invoke(obj, arrayList, file, arrayList2);
|
||||
}
|
||||
}
|
||||
|
||||
static boolean a(String str) {
|
||||
boolean z = false;
|
||||
if (str != null) {
|
||||
Matcher matcher = Pattern.compile("(\\d+)\\.(\\d+)(\\.\\d+)?").matcher(str);
|
||||
if (matcher.matches()) {
|
||||
try {
|
||||
int parseInt = Integer.parseInt(matcher.group(1));
|
||||
int parseInt2 = Integer.parseInt(matcher.group(2));
|
||||
if (parseInt > 2 || (parseInt == 2 && parseInt2 >= 1)) {
|
||||
z = true;
|
||||
}
|
||||
} catch (NumberFormatException unused) {
|
||||
}
|
||||
}
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("VM with version ");
|
||||
sb.append(str);
|
||||
sb.append(z ? " has multidex support" : " does not have multidex support");
|
||||
Log.i("MultiDex", sb.toString());
|
||||
return z;
|
||||
}
|
||||
|
||||
private static void a(ClassLoader classLoader, File file, List<? extends File> list) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, InvocationTargetException, NoSuchMethodException, IOException, SecurityException, ClassNotFoundException, InstantiationException {
|
||||
if (list.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
int i = Build.VERSION.SDK_INT;
|
||||
if (i >= 19) {
|
||||
V19.a(classLoader, list, file);
|
||||
} else if (i >= 14) {
|
||||
V14.a(classLoader, list);
|
||||
} else {
|
||||
V4.a(classLoader, list);
|
||||
}
|
||||
}
|
||||
|
||||
private static void a(Context context) throws Exception {
|
||||
File file = new File(context.getFilesDir(), "secondary-dexes");
|
||||
if (file.isDirectory()) {
|
||||
Log.i("MultiDex", "Clearing old secondary dex dir (" + file.getPath() + ").");
|
||||
File[] listFiles = file.listFiles();
|
||||
if (listFiles == null) {
|
||||
Log.w("MultiDex", "Failed to list secondary dex dir content (" + file.getPath() + ").");
|
||||
return;
|
||||
}
|
||||
for (File file2 : listFiles) {
|
||||
Log.i("MultiDex", "Trying to delete old file " + file2.getPath() + " of size " + file2.length());
|
||||
if (file2.delete()) {
|
||||
Log.i("MultiDex", "Deleted old file " + file2.getPath());
|
||||
} else {
|
||||
Log.w("MultiDex", "Failed to delete old file " + file2.getPath());
|
||||
}
|
||||
}
|
||||
if (!file.delete()) {
|
||||
Log.w("MultiDex", "Failed to delete secondary dex dir " + file.getPath());
|
||||
return;
|
||||
}
|
||||
Log.i("MultiDex", "Deleted old secondary dex dir " + file.getPath());
|
||||
}
|
||||
}
|
||||
|
||||
private static File a(Context context, File file, String str) throws IOException {
|
||||
File file2 = new File(file, "code_cache");
|
||||
try {
|
||||
a(file2);
|
||||
} catch (IOException unused) {
|
||||
file2 = new File(context.getFilesDir(), "code_cache");
|
||||
a(file2);
|
||||
}
|
||||
File file3 = new File(file2, str);
|
||||
a(file3);
|
||||
return file3;
|
||||
}
|
||||
|
||||
private static void a(File file) throws IOException {
|
||||
file.mkdir();
|
||||
if (file.isDirectory()) {
|
||||
return;
|
||||
}
|
||||
File parentFile = file.getParentFile();
|
||||
if (parentFile == null) {
|
||||
Log.e("MultiDex", "Failed to create dir " + file.getPath() + ". Parent file is null.");
|
||||
} else {
|
||||
Log.e("MultiDex", "Failed to create dir " + file.getPath() + ". parent file is a dir " + parentFile.isDirectory() + ", a file " + parentFile.isFile() + ", exists " + parentFile.exists() + ", readable " + parentFile.canRead() + ", writable " + parentFile.canWrite());
|
||||
}
|
||||
throw new IOException("Failed to create directory " + file.getPath());
|
||||
}
|
||||
}
|
13
sources/androidx/multidex/MultiDexApplication.java
Normal file
13
sources/androidx/multidex/MultiDexApplication.java
Normal file
@@ -0,0 +1,13 @@
|
||||
package androidx.multidex;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
|
||||
/* loaded from: classes.dex */
|
||||
public class MultiDexApplication extends Application {
|
||||
@Override // android.content.ContextWrapper
|
||||
protected void attachBaseContext(Context context) {
|
||||
super.attachBaseContext(context);
|
||||
MultiDex.c(this);
|
||||
}
|
||||
}
|
299
sources/androidx/multidex/MultiDexExtractor.java
Normal file
299
sources/androidx/multidex/MultiDexExtractor.java
Normal file
@@ -0,0 +1,299 @@
|
||||
package androidx.multidex;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.Closeable;
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.channels.FileLock;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
/* loaded from: classes.dex */
|
||||
final class MultiDexExtractor implements Closeable {
|
||||
private final File a;
|
||||
private final long b;
|
||||
private final File c;
|
||||
private final RandomAccessFile d;
|
||||
private final FileChannel e;
|
||||
private final FileLock f;
|
||||
|
||||
private static class ExtractedDex extends File {
|
||||
public long a;
|
||||
|
||||
public ExtractedDex(File file, String str) {
|
||||
super(file, str);
|
||||
this.a = -1L;
|
||||
}
|
||||
}
|
||||
|
||||
MultiDexExtractor(File file, File file2) throws IOException {
|
||||
Log.i("MultiDex", "MultiDexExtractor(" + file.getPath() + ", " + file2.getPath() + ")");
|
||||
this.a = file;
|
||||
this.c = file2;
|
||||
this.b = b(file);
|
||||
File file3 = new File(file2, "MultiDex.lock");
|
||||
this.d = new RandomAccessFile(file3, "rw");
|
||||
try {
|
||||
this.e = this.d.getChannel();
|
||||
try {
|
||||
Log.i("MultiDex", "Blocking on lock " + file3.getPath());
|
||||
this.f = this.e.lock();
|
||||
Log.i("MultiDex", file3.getPath() + " locked");
|
||||
} catch (IOException e) {
|
||||
e = e;
|
||||
a(this.e);
|
||||
throw e;
|
||||
} catch (Error e2) {
|
||||
e = e2;
|
||||
a(this.e);
|
||||
throw e;
|
||||
} catch (RuntimeException e3) {
|
||||
e = e3;
|
||||
a(this.e);
|
||||
throw e;
|
||||
}
|
||||
} catch (IOException | Error | RuntimeException e4) {
|
||||
a(this.d);
|
||||
throw e4;
|
||||
}
|
||||
}
|
||||
|
||||
private static long b(File file) throws IOException {
|
||||
long a = ZipUtil.a(file);
|
||||
return a == -1 ? a - 1 : a;
|
||||
}
|
||||
|
||||
List<? extends File> a(Context context, String str, boolean z) throws IOException {
|
||||
List<ExtractedDex> b;
|
||||
Log.i("MultiDex", "MultiDexExtractor.load(" + this.a.getPath() + ", " + z + ", " + str + ")");
|
||||
if (!this.f.isValid()) {
|
||||
throw new IllegalStateException("MultiDexExtractor was closed");
|
||||
}
|
||||
if (z || a(context, this.a, this.b, str)) {
|
||||
if (z) {
|
||||
Log.i("MultiDex", "Forced extraction must be performed.");
|
||||
} else {
|
||||
Log.i("MultiDex", "Detected that extraction must be performed.");
|
||||
}
|
||||
b = b();
|
||||
a(context, str, a(this.a), this.b, b);
|
||||
} else {
|
||||
try {
|
||||
b = a(context, str);
|
||||
} catch (IOException e) {
|
||||
Log.w("MultiDex", "Failed to reload existing extracted secondary dex files, falling back to fresh extraction", e);
|
||||
b = b();
|
||||
a(context, str, a(this.a), this.b, b);
|
||||
}
|
||||
}
|
||||
Log.i("MultiDex", "load found " + b.size() + " secondary dex files");
|
||||
return b;
|
||||
}
|
||||
|
||||
@Override // java.io.Closeable, java.lang.AutoCloseable
|
||||
public void close() throws IOException {
|
||||
this.f.release();
|
||||
this.e.close();
|
||||
this.d.close();
|
||||
}
|
||||
|
||||
private List<ExtractedDex> b() throws IOException {
|
||||
boolean z;
|
||||
String str = this.a.getName() + ".classes";
|
||||
a();
|
||||
ArrayList arrayList = new ArrayList();
|
||||
ZipFile zipFile = new ZipFile(this.a);
|
||||
try {
|
||||
ZipEntry entry = zipFile.getEntry("classes2.dex");
|
||||
int i = 2;
|
||||
while (entry != null) {
|
||||
ExtractedDex extractedDex = new ExtractedDex(this.c, str + i + ".zip");
|
||||
arrayList.add(extractedDex);
|
||||
Log.i("MultiDex", "Extraction is needed for file " + extractedDex);
|
||||
int i2 = 0;
|
||||
boolean z2 = false;
|
||||
while (i2 < 3 && !z2) {
|
||||
int i3 = i2 + 1;
|
||||
a(zipFile, entry, extractedDex, str);
|
||||
try {
|
||||
extractedDex.a = b(extractedDex);
|
||||
z = true;
|
||||
} catch (IOException e) {
|
||||
Log.w("MultiDex", "Failed to read crc from " + extractedDex.getAbsolutePath(), e);
|
||||
z = false;
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("Extraction ");
|
||||
sb.append(z ? "succeeded" : "failed");
|
||||
sb.append(" '");
|
||||
sb.append(extractedDex.getAbsolutePath());
|
||||
sb.append("': length ");
|
||||
sb.append(extractedDex.length());
|
||||
sb.append(" - crc: ");
|
||||
sb.append(extractedDex.a);
|
||||
Log.i("MultiDex", sb.toString());
|
||||
if (!z) {
|
||||
extractedDex.delete();
|
||||
if (extractedDex.exists()) {
|
||||
Log.w("MultiDex", "Failed to delete corrupted secondary dex '" + extractedDex.getPath() + "'");
|
||||
}
|
||||
}
|
||||
z2 = z;
|
||||
i2 = i3;
|
||||
}
|
||||
if (!z2) {
|
||||
throw new IOException("Could not create zip file " + extractedDex.getAbsolutePath() + " for secondary dex (" + i + ")");
|
||||
}
|
||||
i++;
|
||||
entry = zipFile.getEntry("classes" + i + ".dex");
|
||||
}
|
||||
try {
|
||||
zipFile.close();
|
||||
} catch (IOException e2) {
|
||||
Log.w("MultiDex", "Failed to close resource", e2);
|
||||
}
|
||||
return arrayList;
|
||||
} finally {
|
||||
}
|
||||
}
|
||||
|
||||
private List<ExtractedDex> a(Context context, String str) throws IOException {
|
||||
Log.i("MultiDex", "loading existing secondary dex files");
|
||||
String str2 = this.a.getName() + ".classes";
|
||||
SharedPreferences a = a(context);
|
||||
int i = a.getInt(str + "dex.number", 1);
|
||||
ArrayList arrayList = new ArrayList(i + (-1));
|
||||
int i2 = 2;
|
||||
while (i2 <= i) {
|
||||
ExtractedDex extractedDex = new ExtractedDex(this.c, str2 + i2 + ".zip");
|
||||
if (extractedDex.isFile()) {
|
||||
extractedDex.a = b(extractedDex);
|
||||
long j = a.getLong(str + "dex.crc." + i2, -1L);
|
||||
long j2 = a.getLong(str + "dex.time." + i2, -1L);
|
||||
long lastModified = extractedDex.lastModified();
|
||||
if (j2 == lastModified) {
|
||||
String str3 = str2;
|
||||
SharedPreferences sharedPreferences = a;
|
||||
if (j == extractedDex.a) {
|
||||
arrayList.add(extractedDex);
|
||||
i2++;
|
||||
a = sharedPreferences;
|
||||
str2 = str3;
|
||||
}
|
||||
}
|
||||
throw new IOException("Invalid extracted dex: " + extractedDex + " (key \"" + str + "\"), expected modification time: " + j2 + ", modification time: " + lastModified + ", expected crc: " + j + ", file crc: " + extractedDex.a);
|
||||
}
|
||||
throw new IOException("Missing extracted secondary dex file '" + extractedDex.getPath() + "'");
|
||||
}
|
||||
return arrayList;
|
||||
}
|
||||
|
||||
private static boolean a(Context context, File file, long j, String str) {
|
||||
SharedPreferences a = a(context);
|
||||
if (a.getLong(str + "timestamp", -1L) == a(file)) {
|
||||
if (a.getLong(str + "crc", -1L) == j) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static long a(File file) {
|
||||
long lastModified = file.lastModified();
|
||||
return lastModified == -1 ? lastModified - 1 : lastModified;
|
||||
}
|
||||
|
||||
private static void a(Context context, String str, long j, long j2, List<ExtractedDex> list) {
|
||||
SharedPreferences.Editor edit = a(context).edit();
|
||||
edit.putLong(str + "timestamp", j);
|
||||
edit.putLong(str + "crc", j2);
|
||||
edit.putInt(str + "dex.number", list.size() + 1);
|
||||
int i = 2;
|
||||
for (ExtractedDex extractedDex : list) {
|
||||
edit.putLong(str + "dex.crc." + i, extractedDex.a);
|
||||
edit.putLong(str + "dex.time." + i, extractedDex.lastModified());
|
||||
i++;
|
||||
}
|
||||
edit.commit();
|
||||
}
|
||||
|
||||
private static SharedPreferences a(Context context) {
|
||||
return context.getSharedPreferences("multidex.version", Build.VERSION.SDK_INT < 11 ? 0 : 4);
|
||||
}
|
||||
|
||||
private void a() {
|
||||
File[] listFiles = this.c.listFiles(new FileFilter(this) { // from class: androidx.multidex.MultiDexExtractor.1
|
||||
@Override // java.io.FileFilter
|
||||
public boolean accept(File file) {
|
||||
return !file.getName().equals("MultiDex.lock");
|
||||
}
|
||||
});
|
||||
if (listFiles == null) {
|
||||
Log.w("MultiDex", "Failed to list secondary dex dir content (" + this.c.getPath() + ").");
|
||||
return;
|
||||
}
|
||||
for (File file : listFiles) {
|
||||
Log.i("MultiDex", "Trying to delete old file " + file.getPath() + " of size " + file.length());
|
||||
if (file.delete()) {
|
||||
Log.i("MultiDex", "Deleted old file " + file.getPath());
|
||||
} else {
|
||||
Log.w("MultiDex", "Failed to delete old file " + file.getPath());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void a(ZipFile zipFile, ZipEntry zipEntry, File file, String str) throws IOException, FileNotFoundException {
|
||||
InputStream inputStream = zipFile.getInputStream(zipEntry);
|
||||
File createTempFile = File.createTempFile("tmp-" + str, ".zip", file.getParentFile());
|
||||
Log.i("MultiDex", "Extracting " + createTempFile.getPath());
|
||||
try {
|
||||
ZipOutputStream zipOutputStream = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(createTempFile)));
|
||||
try {
|
||||
ZipEntry zipEntry2 = new ZipEntry("classes.dex");
|
||||
zipEntry2.setTime(zipEntry.getTime());
|
||||
zipOutputStream.putNextEntry(zipEntry2);
|
||||
byte[] bArr = new byte[16384];
|
||||
for (int read = inputStream.read(bArr); read != -1; read = inputStream.read(bArr)) {
|
||||
zipOutputStream.write(bArr, 0, read);
|
||||
}
|
||||
zipOutputStream.closeEntry();
|
||||
zipOutputStream.close();
|
||||
if (createTempFile.setReadOnly()) {
|
||||
Log.i("MultiDex", "Renaming to " + file.getPath());
|
||||
if (createTempFile.renameTo(file)) {
|
||||
return;
|
||||
}
|
||||
throw new IOException("Failed to rename \"" + createTempFile.getAbsolutePath() + "\" to \"" + file.getAbsolutePath() + "\"");
|
||||
}
|
||||
throw new IOException("Failed to mark readonly \"" + createTempFile.getAbsolutePath() + "\" (tmp of \"" + file.getAbsolutePath() + "\")");
|
||||
} catch (Throwable th) {
|
||||
zipOutputStream.close();
|
||||
throw th;
|
||||
}
|
||||
} finally {
|
||||
a(inputStream);
|
||||
createTempFile.delete();
|
||||
}
|
||||
}
|
||||
|
||||
private static void a(Closeable closeable) {
|
||||
try {
|
||||
closeable.close();
|
||||
} catch (IOException e) {
|
||||
Log.w("MultiDex", "Failed to close resource", e);
|
||||
}
|
||||
}
|
||||
}
|
71
sources/androidx/multidex/ZipUtil.java
Normal file
71
sources/androidx/multidex/ZipUtil.java
Normal file
@@ -0,0 +1,71 @@
|
||||
package androidx.multidex;
|
||||
|
||||
import android.support.v4.media.session.PlaybackStateCompat;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.util.zip.CRC32;
|
||||
import java.util.zip.ZipException;
|
||||
|
||||
/* loaded from: classes.dex */
|
||||
final class ZipUtil {
|
||||
|
||||
static class CentralDirectory {
|
||||
long a;
|
||||
long b;
|
||||
|
||||
CentralDirectory() {
|
||||
}
|
||||
}
|
||||
|
||||
static long a(File file) throws IOException {
|
||||
RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r");
|
||||
try {
|
||||
return a(randomAccessFile, a(randomAccessFile));
|
||||
} finally {
|
||||
randomAccessFile.close();
|
||||
}
|
||||
}
|
||||
|
||||
static CentralDirectory a(RandomAccessFile randomAccessFile) throws IOException, ZipException {
|
||||
long length = randomAccessFile.length() - 22;
|
||||
if (length >= 0) {
|
||||
long j = length - PlaybackStateCompat.ACTION_PREPARE_FROM_SEARCH;
|
||||
long j2 = j >= 0 ? j : 0L;
|
||||
int reverseBytes = Integer.reverseBytes(101010256);
|
||||
do {
|
||||
randomAccessFile.seek(length);
|
||||
if (randomAccessFile.readInt() == reverseBytes) {
|
||||
randomAccessFile.skipBytes(2);
|
||||
randomAccessFile.skipBytes(2);
|
||||
randomAccessFile.skipBytes(2);
|
||||
randomAccessFile.skipBytes(2);
|
||||
CentralDirectory centralDirectory = new CentralDirectory();
|
||||
centralDirectory.b = Integer.reverseBytes(randomAccessFile.readInt()) & 4294967295L;
|
||||
centralDirectory.a = Integer.reverseBytes(randomAccessFile.readInt()) & 4294967295L;
|
||||
return centralDirectory;
|
||||
}
|
||||
length--;
|
||||
} while (length >= j2);
|
||||
throw new ZipException("End Of Central Directory signature not found");
|
||||
}
|
||||
throw new ZipException("File too short to be a zip file: " + randomAccessFile.length());
|
||||
}
|
||||
|
||||
static long a(RandomAccessFile randomAccessFile, CentralDirectory centralDirectory) throws IOException {
|
||||
CRC32 crc32 = new CRC32();
|
||||
long j = centralDirectory.b;
|
||||
randomAccessFile.seek(centralDirectory.a);
|
||||
byte[] bArr = new byte[16384];
|
||||
int read = randomAccessFile.read(bArr, 0, (int) Math.min(PlaybackStateCompat.ACTION_PREPARE, j));
|
||||
while (read != -1) {
|
||||
crc32.update(bArr, 0, read);
|
||||
j -= read;
|
||||
if (j == 0) {
|
||||
break;
|
||||
}
|
||||
read = randomAccessFile.read(bArr, 0, (int) Math.min(PlaybackStateCompat.ACTION_PREPARE, j));
|
||||
}
|
||||
return crc32.getValue();
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user