| Index: base/android/java/src/org/chromium/base/multidex/ChromiumClassLoader.java
|
| diff --git a/base/android/java/src/org/chromium/base/multidex/ChromiumClassLoader.java b/base/android/java/src/org/chromium/base/multidex/ChromiumClassLoader.java
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..49bfb5c594daead4be786585c4c97edcd7f5f6f2
|
| --- /dev/null
|
| +++ b/base/android/java/src/org/chromium/base/multidex/ChromiumClassLoader.java
|
| @@ -0,0 +1,120 @@
|
| +// Copyright 2017 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +package org.chromium.base.multidex;
|
| +
|
| +import static org.chromium.base.Reflect.getField;
|
| +
|
| +import android.annotation.TargetApi;
|
| +import android.content.Context;
|
| +import android.content.ContextWrapper;
|
| +import android.os.Build;
|
| +
|
| +import dalvik.system.PathClassLoader;
|
| +
|
| +import org.chromium.base.BuildConfig;
|
| +import org.chromium.base.ContextUtils;
|
| +import org.chromium.base.FileUtils;
|
| +import org.chromium.base.Log;
|
| +import org.chromium.base.Reflect;
|
| +
|
| +import java.lang.reflect.InvocationTargetException;
|
| +import java.lang.reflect.Method;
|
| +import java.util.Collections;
|
| +import java.util.HashSet;
|
| +
|
| +public class ChromiumClassLoader extends PathClassLoader {
|
| + private static final String TAG = "ChromiumClassLoader";
|
| + private static final String SEPERATOR = ",";
|
| + private static final String MAIN_DEX_LIST_FILE = "classes.dex.zip_java_list.csv";
|
| +
|
| + private ClassLoader mClassLoaderDelegate;
|
| + private HashSet<String> mMainDexClasses;
|
| +
|
| + @TargetApi(Build.VERSION_CODES.N)
|
| + private static ChromiumClassLoader create(Context context) {
|
| + try {
|
| + Object packageInfo = getField(getContextImpl(context), "mPackageInfo");
|
| + ClassLoader parent = (ClassLoader) Reflect.getField(packageInfo, "mClassLoader");
|
| + return new ChromiumClassLoader(context.getPackageCodePath(), parent);
|
| + } catch (Exception e) {
|
| + Log.d(TAG, "Encountered exception: " + e.getMessage());
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + private ChromiumClassLoader(String dexPath, ClassLoader parent) {
|
| + super(dexPath, parent);
|
| + mClassLoaderDelegate = parent;
|
| + }
|
| +
|
| + @Override
|
| + public Class<?> loadClass(String name) throws ClassNotFoundException {
|
| + assert mMainDexClasses != null;
|
| + Log.d(TAG, "Loading class: " + name);
|
| + if ((name.startsWith("com.google") || name.startsWith("org.chromium"))
|
| + && !mMainDexClasses.contains(name)) {
|
| + Log.wtf(TAG, "ERROR loading class: " + name);
|
| + throw new AssertionError();
|
| + }
|
| + return mClassLoaderDelegate.loadClass(name);
|
| + }
|
| +
|
| + private void buildMainDexList() {
|
| + String file = FileUtils.extractAsset(MAIN_DEX_LIST_FILE);
|
| + mMainDexClasses = new HashSet<String>();
|
| + Collections.addAll(mMainDexClasses, file.split(SEPERATOR));
|
| + }
|
| +
|
| + /**
|
| + *
|
| + * @param context
|
| + * @param cl
|
| + */
|
| + private static void installClassLoader(Context context, ClassLoader cl) {
|
| + try {
|
| + Object packageInfo = getField(getContextImpl(context), "mPackageInfo");
|
| + Reflect.setField(packageInfo, "mClassLoader", cl);
|
| + Thread.currentThread().setContextClassLoader(cl);
|
| +
|
| + } catch (Exception e) {
|
| + Log.d("ChromiumClassLoader", "Encountered exception: " + e.getMessage());
|
| + }
|
| + }
|
| +
|
| + private static Context getContextImpl(Context context) {
|
| + while (context instanceof ContextWrapper) {
|
| + ContextWrapper wrapper = (ContextWrapper) context;
|
| + if (wrapper.getBaseContext() == null || wrapper.getBaseContext() == context) {
|
| + break;
|
| + }
|
| + context = wrapper.getBaseContext();
|
| + }
|
| + return context;
|
| + }
|
| +
|
| + private static boolean isIsolatedProcess() {
|
| + try {
|
| + Method isIsolatedMethod = android.os.Process.class.getMethod("isIsolated");
|
| + Object retVal = isIsolatedMethod.invoke(null);
|
| + return retVal != null && retVal instanceof Boolean && ((Boolean) retVal);
|
| + } catch (NoSuchMethodException e) {
|
| + e.printStackTrace();
|
| + } catch (IllegalAccessException e) {
|
| + e.printStackTrace();
|
| + } catch (InvocationTargetException e) {
|
| + e.printStackTrace();
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + public static void initDebugClassLoader() {
|
| + if (!BuildConfig.isOfficialBuild() && isIsolatedProcess()) {
|
| + Context appContext = ContextUtils.getApplicationContext();
|
| + ChromiumClassLoader cl = create(appContext);
|
| + cl.buildMainDexList();
|
| + installClassLoader(appContext, cl);
|
| + }
|
| + }
|
| +}
|
|
|