Direct-Load-apk 源代码分析
来源:互联网 发布:广义逆矩阵求法 编辑:程序博客网 时间:2024/04/27 14:11
这款框架结合了Dynamic-Load-apk 和 PluginMgr 的弱点,使用了新的思路,成功实现了启动普通的apk。
1.Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler());
可以设置所有未捕获异常的Handler
2.一开始直接往 LActivityProxy 也就是代理Activity 中跳
3.总体理念:代理+伪装注入
4.在代理Activity 中,直接初始化插件APK
调用loadAPK 将插件的路径和当前的Context 传递给插件模型类,接着,依次调用
fillPluginRes(plugin);
if (!plugin.isOver()) {
fillPluginInfo(plugin);
}
fillPluginLoader(plugin);
fillPluginApplication(plugin);
填充并初始化插件模型类的资源、信息、ClassLoader、Application
难点有哪些呢?
首先,在fillRes 也就是加载资源函数中:
AssetManager assetManager = AssetManager.class.newInstance();
Reflect assetRef = Reflect.on(assetManager);
assetRef.call("addAssetPath", plugin.getPluginPath());
plugin.setPluginAssetManager(assetManager);
Resources superRes = super.getResources();
Resources pluginRes = new Resources(assetManager,
superRes.getDisplayMetrics(),
superRes.getConfiguration());
plugin.setPluginRes(pluginRes);
Resources.Theme pluginTheme = plugin.getPluginRes().newTheme();
pluginTheme.setTo(super.getTheme());
plugin.setCurrentPluginTheme(pluginTheme);
注意带颜色的字:将当前代理Activity 的主题给了plugin
在fillLoader 也就是加载ClassLoader 过程中,它自定义了一个ClassLoader 继承了DexClassLoader ,在内部利用HashMap 实现了一个缓存。HashMap<String,DexClassLoader> ,String即为APK 的路径
在fillApplication 中有这么一句
Application pluginApp = (Application) loader.loadClass(appName).newInstance();
Reflect.on(pluginApp).call("attach", getApplicationContext());
Application 的attach 是一个隐藏的方法,实际调用了 ConTextWrapper 的 attachBaseContext 方法,实现了插件Application 的this 指针的正确调用.
5.如何做到Activity 的生命周期的呢?
我们知道,通过ClassLoader 直接加载出来的Activity 并没有生命周期,一般,有这么几种解决方法:
(1).替换ActivityThread LoadedApk中的mClassLoader
(2).合并PathClassLoader和DexClassLoader中的dexElements数组
缺点:需要在Host 程序的清单文件中声明插件Activity 的内容
(3).通过代理Activity,在代理Activity 中onXXX() 方法中执行插件的方法
缺点:插件Activity 不能调用this 指针,需要把每个生命周期方法重写一次,并且插件方需要直接或间接反向调用Host方的setContentView 方法去设定视图,非常不方便
(4).Host 方热部署动态生成一个 Activity extends 插件Activity
缺点:在ART 环境下无法正确运行
(5).Host方先通过反射调用插件 Activity 的 attachBaseContext 方法 ,将mBase 设置成代理Activity,保证this 指针能正确使用,再将插件 Activity 中的所有『环境』变量设置为代理Activity 的变量进行伪装,如下:
attachBaseContextpluginRef.set("mBase", proxy);
pluginRef.set("mDecor", proxyRef.get("mDecor"));
pluginRef.set("mTitleColor", proxyRef.get("mTitleColor"));
pluginRef.set("mWindowManager", proxyRef.get("mWindowManager"));
pluginRef.set("mWindow", proxy.getWindow());
pluginRef.set("mManagedDialogs", proxyRef.get("mManagedDialogs"));
pluginRef.set("mCurrentConfig", proxyRef.get("mCurrentConfig"));
pluginRef.set("mSearchManager", proxyRef.get("mSearchManager"));
pluginRef.set("mMenuInflater", proxyRef.get("mMenuInflater"));
pluginRef.set("mConfigChangeFlags", proxyRef.get("
...
伪装之后,再通过 getPluginRef().call("onCreate", saveInstance); 手动调用插件Activity 的onCreate 方法,就能让插件Activity 正确调用其他的生命周期函数了
6.如何进行Activity 的跳转呢?
在对Activity 进行『伪装』的时候,顺手将Activity 中的 mInstrumentation 修改成了自定义的 Instrumentation ,众所周知,Activity的跳转实际就是通过它进行的,自定义 Instrumentation 将目标改成代理Activity 即可:
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
Intent gotoPluginOrHost = new Intent();
ComponentName componentName = intent.getComponent();
String className = componentName.getClassName();
String packageName = componentName.getPackageName();
//Toast.makeText(who, className, Toast.LENGTH_LONG).show();
gotoPluginOrHost.setClass(who, LActivityProxy.class);
gotoPluginOrHost.putExtra(LPluginConfig.KEY_PLUGIN_DEX_PATH, LPluginManager.finalApkPath);
gotoPluginOrHost.putExtra(LPluginConfig.KEY_PLUGIN_ACT_NAME,className);
ActivityResult result =instrumentRef.call("execStartActivity",who,contextThread,token,target,gotoPluginOrHost,requestCode,options).get();
return result;
}
2 0
- Direct-Load-apk 源代码分析
- Direct-Load-apk启动插件的原理
- Direct-Load-apk启动插件的原理
- Direct-Load-apk启动插件的原理
- Direct-Load-apk启动插件的原理
- http load 源代码分析
- Android 插件平台技术 <二> 基本介绍和direct-load-apk介绍
- [插件]dynamic-load-apk的源码分析
- Ext Direct Spring Tree Load Method
- classloader load apk
- Direct Message功能简单分析
- Apk得到Java源代码
- android apk源代码反编译
- APK反编译--查看源代码
- OCP052_100_Situations in Which Direct Path Load Is Not Used(译)
- direct path read 等待事件分析
- Direct IO和Buffered IO简单分析
- TThreadedSelectorServer 介绍及 Direct Memory OOM 分析
- iOS开发之如何跳到系统设置里的WiFi界面
- 单点登录SSO
- JDBC基本源码演示增删改查
- Android Design Support Library实践之Snackbar
- flume架构介绍!
- Direct-Load-apk 源代码分析
- Netty使用Marshalling传输信息
- BW从数据源2LIS_02_ITM实现增量抽数
- 12.php外观模式
- 操作系统中长期调度、中期调度和短期调度之间的区别
- 【Redis笔记(三)】 Redis数据结构 - hash哈希
- 名字的漂亮度
- apk安装和优化原理
- 数据挖掘,第一面