插件化:动态加载类

参考:
1、http://blog.csdn.net/yulong0809
2、http://weishu.me/

主要涉及到基础知识:Binder机制、代理模式、dex类加载、app启动过程、反射hook等。

动态加载类

1、通过Dex:类加载过程得知:类是又classloader加载的,所有看一下classloader是怎么获取的;
2、在app启动过程中,classLoader 是通过r.packageInfo.getClassLoader()获取的,而r.packageInfo是一个LoadedApk类型的对象;
3、LoadedApk对象是APK文件在内存中的表示; Apk文件的相关信息,诸如Apk文件的代码和资源,甚至代码里面的Activity,Service等四大组件的信息我们都可以通过此对象获取;
4、r.packageInfo是如何赋值的?查看源码得知
r.packageInfo = getPackageInfoNoCheck(r.activityInfo.applicationInfo, r.compatInfo);
getPackageInfoNoCheck()->getPackageInfo()
5、在ActivityThread.java中维护着一个ArrayMap:key = String,value = loadedApk对象mPackages,此对象是通过packageName进行键值对保存的;
6、在getPackageInfo()中判断此packageName的loadedApk是否存在,存在,则返回,反之,则创建一个新的,并保存在mPackages中。

实现思路

思路一
1、加载我们的插件dex,需要一个classloader,所以我们可以通过自己定义一个我们自己的classloader来管理所有的dex;
2、classloader是通过loadedApk获取的,所有我们要定义一个我们自己的loadedApk;
3、loadedApk是保存在ActivityThread.java中的一个ArrayMap对象mPackages中的,通过packageName作为key, 所以我们只要把这个mPackages中的loadedApk替换成我们自己的loadedApk就可以了。
缺陷:
1、需要hook系统的n多个类和方法;
2、在构造loadedApk时,需要一个ApplicationInfo对象,而这个ApplicationInfo对象是通过解析AndroidManifest.xml得到的,所以我们还要手动解析AndroidManifest.xml文件,过程及其复杂。
应用:360的DroidPlugin就是用的这个思路。

思路二
将我们的插件的信息告诉系统的classloader,让其帮忙加载。
1、我们都知道class文件是通过BaseDexClassloader的findClass()方法获取的,最终是在DexPathList中的一个Element[]数组中获取的,数组Element[]中的元素就是一个 Element对象,此对象维护着一个dex文件,即DexFile。所以我们只要把我们的插件dex存储在Element[]数组中就可以让系统来帮我们加载了;
a. 获取系统的PathClassloader pathClassloader=(PathClassloader)context.getClassloader(); context 是Application类型的;
b.定义一个DexClassloader,把我们插件的路径dexPath传进去;
c.获取pathClassloader和dexClassloader的DexPathList对象:rootDexPathList、pluginDexPathList;
d.根据rootDexPathList和pluginDexPathList获取其Element[]数组:rootElements和pluginElements;
e.新建一个Array: allElements,合并两个Element[]数组;
f.将合并后的allElements数组重新给rooDexPathList中的dexElements赋值。

2、但是activity要在AndroidManifest.xml中注册,我们的插件并没有在宿主的AndroidManifest.xml中注册,所以我们要通过hook的思想,先可以用一个假的activity在宿主的AndroidManifest.xml中占坑,使用它去系统底层校验合法性,然后到真正创建activity的时候,替换成我们插件的activity。
a. 验证activity的合法性是在Instrumentatin.java->execStartActivity() 方法中的checkStartActivityResult(result,intent);而其中的result= ActivityManagerNative.getDefault().startActivity(…); 所以得想办法修改这个result的值;
b.然后查看getDefault()的源码,有个变量gDefault,是一个Singleton 对象,查看Singleton源码,有个mInstance的成员变量;
c.本来ActivityManagerNative.getDefault()返回的就是一个ActivityManagerService的代理类,所以我们只要重新给Singleton中的成员变量:mInstance设一个我们自己的ActivityManagerService的代理类就可以了,这个代理类主要是拦截startActivity方法,将其中的activity替换成我们的占坑activity,这样就可以欺骗系统,完成校验。
d.在完成校验后,就要把我们正真的activity替换回来了。在启动activity的过程中,在ActivityThread.java这个类中有个handler用于接收消息,activity启动的消息也是传到这里的,所以我们就在这里通过hook的思想,把消息中的参数改一改,即把intent中的activity改成我们自己的activity就可以了。

备注:一定要加权限
android:name=”android.permission.READ_EXTERNAL_STORAGE” android:name=”android.permission.WRITE_EXTERNAL_STORAGE”

demo下载:暂时无法加载资源

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值