android开源框架06-08插件化

常见第三方插件化工具

droidplugin 已弃用;
replugin 360的 在更新 耦合度低推荐;
VirtualAPK 滴滴的在更新 耦合度高推荐;
dynamicAPK携程 搜了下百度没最新的

反射影响性能原因

1 产生大量的零时对象
2 检查可见性
3 如果经常调用某块,会生成字节码 (没有优化的,不超过1000次就还好)
4 类型转换 封箱拆箱

ClassLoader

bootclassloader 加载系统的类 sdk 的
pathclassloader 加载自己写的类 应用的
dexclassloader 8.0之后 和pathclassloader没什么区别;这个是谷歌考虑兼容 留给用户用的,而pathclassloader是谷歌自己用的

dexclassloader—ClassLoader.loadclass双亲委派机制 到 pathClassLoader的 loadclass 然后再到 bootclassLoader 的loadclass (这个就在ClassLoader 里面)

双亲委派机制
避免重复加载
安全性,防止核心api串改

Basedexclassloader 中的dexpath 中的dexelement数组
findclass 主要关注自己的, 其中element[] dexElements 是所有类加载 element是具体 的类;
我们要做的是在dexElements上面加上插件的类 一起打包

类加载

  1. 获取宿主dexElements
  2. 获取插件dexElements
  3. 合并两个dexElements
  4. 将新的dexElements 赋值到 宿主dexElements
  5. dexElements -- DexPathList类的对象 -- BaseDexClassLoader的对象,类加载器
  6. 获取的是宿主的类加载器 --- 反射 dexElements 宿主
  7. 获取的是插件的类加载器 --- 反射 dexElements 插件
            Class clazz= Class.forName("dalvik.system.BaseDexClassLoader");
            Field pathListField = clazz.getDeclaredField("pathList");
            pathListField.setAccessible(true);

            Class dexPathListClass = Class.forName("dalvik.system.DexPathList");
            Field dexElementsField = dexPathListClass.getDeclaredField("dexElements");
            dexElementsField.setAccessible(true);

            ClassLoader pathClassLoader = context.getClassLoader();
            Object hostPathList = pathListField.get(pathClassLoader);
            Object[] hostDexElements = (Object[]) dexElementsField.get(hostPathList);

            ClassLoader pluginClassLoader = new DexClassLoader("",context.getCacheDir().getAbsolutePath(),"",pathClassLoader);
            Object pluginPathList = pathListField.get(pluginClassLoader);
            Object[] pluginDexElements = (Object[]) dexElementsField.get(pluginPathList);

            Object[] newDexElements = (Object[]) Array.newInstance(hostDexElements.getClass().getComponentType(),
                    hostDexElements.length+pluginDexElements.length);
            System.arraycopy(hostDexElements,0,newDexElements,0,hostDexElements.length);
            System.arraycopy(pluginDexElements,0,newDexElements,hostDexElements.length,pluginDexElements.length);

            dexElementsField.set(hostDexElements,newDexElements);

activity启动 29版本android10

  1. Activity
    startActivityForResult 调用 Instrumentation.execStartActivity
  2. Instrumentation
    这里进行hook 进行ams替换
public static IActivityTaskManager getService(){
  return IActivityTaskManagerSingleton.get();
}
  1. ActivityTaskManagerService
    用途管理Activity及其容器,8以后加入的分摊AMS职责的
    startActivity 到 startActivityAsUser ...excute()
  2. ActivityStarter
    ActivityStarter.excute开启Activity旅程;处理请求参数和一些检查;
    startActivityUnchecked...resumeFocusedStacksTopActivies
  3. RootActivityContainer(自己跟的是这个,网上有文章说RootWindowContainer?空了看看)
    resumeTopActivityUncheckedLocked
  4. ActivityStack TaskRecord有关的处理
    resumeTopActivityInnerLocked中
    mStackSupervisor.startSpecificActivity
  5. ActivityStackSupervisor
    对ActivityStack的管理
  6. ActivityStackSupervisor
    realStartActivityLocked中
    clientTransaction.addCallback(LaunchActivityItem
    mService.getLifecycleManager().scheduleTransaction(clientTransaction); --ClientLifecycleManager 通过binder联系启动客户端activity
  7. ClientLifecycleManager
    scheduleTransaction IApplicationThread 到客户端

  1. ApplicationThread -------回到客户端
    ApplicationThread的scheduleTransaction调用ActivityThread的此方法,实际是ClientTransactionHandler里面的
  2. ClientTransactionHandler
    sendmessage EXCUTE_TRANSACTION 发送消息
  3. ActivityThread 中的H mH
    到handler里面处理 handleMessage EXCUTE_TRANSACTION
    msg.obj 这里进行hook 处理返回的intent的替换

Hook AMS 29版本

  1. 反射获取IActivityTaskManager 和Singleton
  2. 动态代理 把startActivity 前把intent替换为插件代理Activity(intent中要加入插件activity的intent)
  3. 注意:动态代理要替换IActivityTaskManager 才有效果

Hook Handler 29版本

  1. 来个Handler.callback 里面处理159 EXCUTE_TRANSACTION
  2. 通过ClientTransaction 循环 mActivityCallbacks 拿到 LaunchActivityItem(ClientTransactionItem的实现)实例 得到mIntent 换回来
    4.callback要替换系统的 反射来替换

Resource

  1. 通过AssetManager做资源处理
  2. 反射 调用 addAssetPath 新加一份插件的资源
  3. new Resources 来得到插件的Resource
  4. 插件要自己新建context (通过ContextThemeWrapper)
  5. 在新建的context里面 通过反射把mResources换掉,换成插件的
  6. 完工

你可能感兴趣的:(android开源框架06-08插件化)