插件化专题

插件化类加载

2017-08-20  本文已影响0人  丢底很远

插件化框架实现:基于kotlin的插件化框架

Java类加载

类加载机制

ClassLife.png

加载阶段

连接阶段

初始化阶段

Java 类加载器

类加载器的双亲委托模型

Android类加载

Android 类加载器

Android类加载器主要是DexClassLoader和PathClassLoader,两者的区别是:

DexClassLoader版本差异

API 9 - 13

DexClassLoader

public class DexClassLoader extends ClassLoader {
    private static final boolean VERBOSE_DEBUG = false;
    /* constructor args, held for init */
    private final String mRawDexPath;
    private final String mRawLibPath;
    private final String mDexOutputPath;
    /*
     * Parallel arrays for jar/apk files.
     *
     * (could stuff these into an object and have a single array;
     * improves clarity but adds overhead)
     */
    private final File[] mFiles;         // source file Files, for rsrc URLs
    private final ZipFile[] mZips;       // source zip files, with resources
    private final DexFile[] mDexs;       // opened, prepped DEX files
 
    // ....
}

API > 13

DexClassLoader相关类

public class DexClassLoader extends BaseDexClassLoader {
    public DexClassLoader(String dexPath, String optimizedDirectory,
            String librarySearchPath, ClassLoader parent) {
        super(dexPath, new File(optimizedDirectory), librarySearchPath, parent);
    }
}
public class BaseDexClassLoader extends ClassLoader {
    private final DexPathList pathList;
    
    public BaseDexClassLoader(String dexPath, File optimizedDirectory,
            String librarySearchPath, ClassLoader parent) {
        super(parent);
        this.pathList = new DexPathList(this, dexPath, librarySearchPath, optimizedDirectory);
    }
    
    // ...
}
final class DexPathList {
    /** class definition context */
    private final ClassLoader definingContext;
    /**
     * List of dex/resource (class path) elements.
     * Should be called pathElements, but the Facebook app uses reflection
     * to modify 'dexElements' (http://b/7726934).
     */
    private Element[] dexElements;

    // ...
  
    static class Element {
        private final File dir;
        private final boolean isDirectory;
        private final File zip;
        private final DexFile dexFile;
        
        // ...
    }
}

ODEX过程

App ClassLoader Hook点

private void handleBindApplication(AppBindData data) {
  
  // ...
  data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);
  // ...
  
  final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);
  // 下面代码中也创建ContextImpl,这里应该需要先用到ContextImpl的信息,这里
  
  
  // 创建ApplicationInfo 
  ApplicationInfo instrApp = new ApplicationInfo();
  instrApp.packageName = ii.packageName;
  instrApp.sourceDir = ii.sourceDir;
  instrApp.publicSourceDir = ii.publicSourceDir;
  instrApp.splitSourceDirs = ii.splitSourceDirs;
  instrApp.splitPublicSourceDirs = ii.splitPublicSourceDirs;
  instrApp.dataDir = ii.dataDir;
  instrApp.nativeLibraryDir = ii.nativeLibraryDir;
  // 获取或创建LoadedApk
  LoadedApk pi = getPackageInfo(instrApp, data.compatInfo,
          appContext.getClassLoader(), false, true, false);
  ContextImpl instrContext = ContextImpl.createAppContext(this, pi);
  
  try {
      java.lang.ClassLoader cl = instrContext.getClassLoader();
      mInstrumentation = (Instrumentation)
          cl.loadClass(data.instrumentationName.getClassName()).newInstance();
  } catch (Exception e) {
      throw new RuntimeException(
          "Unable to instantiate instrumentation "
          + data.instrumentationName + ": " + e.toString(), e);
  }

  mInstrumentation.init(this, instrContext, appContext,
         new ComponentName(ii.packageName, ii.name), data.instrumentationWatcher,
         data.instrumentationUiAutomationConnection);
  
  // ...
  
  // 创建Application
  Application app = data.info.makeApplication(data.restrictedBackupMode, null);
  mInitialApplication = app;
  
  // 调用Instrumentation的onCreate()方法
  mInstrumentation.onCreate(data.instrumentationArgs);
  
  // 调用Application的onCreate()方法
  mInstrumentation.callApplicationOnCreate(app);
}
public final LoadedApk getPackageInfoNoCheck(ApplicationInfo ai,                                                CompatibilityInfo compatInfo) {
  return getPackageInfo(ai, compatInfo, null, false, true, false);
}

private LoadedApk getPackageInfo(ApplicationInfo aInfo, CompatibilityInfo compatInfo,
        ClassLoader baseLoader, boolean securityViolation, boolean includeCode,
        boolean registerPackage) {
    // 根据包名加载缓存中的LoadedApk 或 创建LoadedApk
}
public ClassLoader getClassLoader() {
  synchronized (this) {
      if (mClassLoader != null) {
          return mClassLoader;
      }

      if (mIncludeCode && !mPackageName.equals("android")) {
        // ...
        mClassLoader = ApplicationLoaders.getDefault().getClassLoader(zip, lib,
                    mBaseClassLoader);
      } else {
        if (mBaseClassLoader == null) {
           mClassLoader = ClassLoader.getSystemClassLoader();
        } else {
           mClassLoader = mBaseClassLoader;
        }
      }
      return mClassLoader;
    }
}

ZenusPlugin 类加载

ZeusClassLoader

ZeusHotfixClassLoader

加载插件代码

/**
 * 启动插件
 *
 */
public void startPlugin() {
    PluginManager.loadLastVersionPlugin(MyApplication.PLUGIN_TEST);
    try {
        Class cl = PluginManager.mNowClassLoader.loadClass(PluginManager.getPlugin(MyApplication.PLUGIN_TEST).getPluginMeta().mainClass);
        Intent intent = new Intent(this, cl);
        //这种方式为通过在宿主AndroidManifest.xml中预埋activity实现
//            startActivity(intent);
        //这种方式为通过欺骗android系统的activity存在性校验的方式实现
        PluginManager.startActivity(this,intent);
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
}

Small 类加载

VirtualAPK

单ClassLoader vs 多ClassLoader

上一篇下一篇

猜你喜欢

热点阅读