android開源框架06-08插件化

常見第三方插件化工具

droidplugin 已棄用;
replugin 360的 在更新 耦合度低推薦;
VirtualAPK 滴滴的在更新 耦合度高推薦;
dynamicAPK攜程 搜了下百度沒最新的

反射影響性能原因

1 產生大量的零時對象
2 檢查可見性
3 如果經(jīng)常調用某塊,會生成字節(jié)碼 (沒有優(yōu)化的,不超過1000次就還好)
4 類型轉換 封箱拆箱

ClassLoader

bootclassloader 加載系統(tǒng)的類 sdk 的
pathclassloader 加載自己寫的類 應用的
dexclassloader 8.0之后 和pathclassloader沒什么區(qū)別;這個是谷歌考慮兼容 留給用戶用的,而pathclassloader是谷歌自己用的

dexclassloader—ClassLoader.loadclass雙親委派機制 到 pathClassLoader的 loadclass 然后再到 bootclassLoader 的loadclass (這個就在ClassLoader 里面)

雙親委派機制
避免重復加載
安全性,防止核心api串改

Basedexclassloader 中的dexpath 中的dexelement數(shù)組
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旅程;處理請求參數(shù)和一些檢查;
    startActivityUnchecked...resumeFocusedStacksTopActivies
  3. RootActivityContainer(自己跟的是這個,網(wǎng)上有文章說RootWindowContainer?空了看看)
    resumeTopActivityUncheckedLocked
  4. ActivityStack TaskRecord有關的處理
    resumeTopActivityInnerLocked中
    mStackSupervisor.startSpecificActivity
  5. ActivityStackSupervisor
    對ActivityStack的管理
  6. ActivityStackSupervisor
    realStartActivityLocked中
    clientTransaction.addCallback(LaunchActivityItem
    mService.getLifecycleManager().scheduleTransaction(clientTransaction); --ClientLifecycleManager 通過binder聯(lián)系啟動客戶端activity
  7. ClientLifecycleManager
    scheduleTransaction IApplicationThread 到客戶端

  1. ApplicationThread -------回到客戶端
    ApplicationThread的scheduleTransaction調用ActivityThread的此方法,實際是ClientTransactionHandler里面的
  2. ClientTransactionHandler
    sendmessage EXCUTE_TRANSACTION 發(fā)送消息
  3. ActivityThread 中的H mH
    到handler里面處理 handleMessage EXCUTE_TRANSACTION
    msg.obj 這里進行hook 處理返回的intent的替換

Hook AMS 29版本

  1. 反射獲取IActivityTaskManager 和Singleton
  2. 動態(tài)代理 把startActivity 前把intent替換為插件代理Activity(intent中要加入插件activity的intent)
  3. 注意:動態(tài)代理要替換IActivityTaskManager 才有效果

Hook Handler 29版本

  1. 來個Handler.callback 里面處理159 EXCUTE_TRANSACTION
  2. 通過ClientTransaction 循環(huán) mActivityCallbacks 拿到 LaunchActivityItem(ClientTransactionItem的實現(xiàn))實例 得到mIntent 換回來
    4.callback要替換系統(tǒng)的 反射來替換

Resource

  1. 通過AssetManager做資源處理
  2. 反射 調用 addAssetPath 新加一份插件的資源
  3. new Resources 來得到插件的Resource
  4. 插件要自己新建context (通過ContextThemeWrapper)
  5. 在新建的context里面 通過反射把mResources換掉,換成插件的
  6. 完工
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容