android 插件加载机制之二

------本文转载自 Android插件化原理解析——插件加载机制 

    这一系列的文章实在是写的好!

5 Hook ClassLoader

从上述分析中我们得知,在获取LoadedApk的过程中使用了一份缓存数据;

这个缓存数据是一个Map,从包名到LoadedApk的一个映射。正常情况下,我们的插件肯定不会存在于这个对象里面;

但是如果我们手动把我们插件的信息添加到里面呢?系统在查找缓存的过程中,会直接命中缓存!

进而使用我们添加进去的LoadedApk的ClassLoader来加载这个特定的Activity类!这样我们就能接管我们自己插件类的加载过程了!

这个缓存对象mPackages存在于ActivityThread类中;老方法,我们首先获取这个对象:

// 先获取到当前的ActivityThread对象
Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");
Method currentActivityThreadMethod = activityThreadClass.getDeclaredMethod("currentActivityThread");
currentActivityThreadMethod.setAccessible(true);
Object currentActivityThread = currentActivityThreadMethod.invoke(null);

// 获取到 mPackages 这个静态成员变量, 这里缓存了dex包的信息
Field mPackagesField = activityThreadClass.getDeclaredField("mPackages");
mPackagesField.setAccessible(true);
Map mPackages = (Map) mPackagesField.get(currentActivityThread);

拿到这个Map之后接下来怎么办呢?我们需要填充这个map,把插件的信息塞进这个map里面,

以便系统在查找的时候能命中缓存。但是这个填充这个Map我们出了需要包名之外,

还需要一个LoadedApk对象;如何创建一个LoadedApk对象呢?

我们当然可以直接反射调用它的构造函数直接创建出需要的对象,但是万一哪里有疏漏,构造参数填错了怎么办?

又或者Android的不同版本使用了不同的参数,导致我们创建出来的对象与系统创建出的对象不一致,无法work怎么办?

因此我们需要使用与系统完全相同的方式创建LoadedApk对象;从上文分析得知,

系统创建LoadedApk对象是通过getPackageInfo来完成的,因此我们可以调用这个函数来创建LoadedApk对象;

但是这个函数是private的,我们无法使用。

有的童鞋可能会有疑问了,private不是也能反射到吗?我们确实能够调用这个函数,

但是private表明这个函数是内部实现,或许那一天Google高兴,把这个函数改个名字我们就直接GG了;

但是public函数不同,public被导出的函数你无法保证是否有别人调用它,因此大部分情况下不会修改;

我们最好调用public函数来保证尽可能少的遇到兼容性问题。

(当然,如果实在木有路可以考虑调用私有方法,自己处理兼容性问题,这个我们以后也会遇到)

间接调用getPackageInfo这个私有函数的public函数有同名的getPackageInfo系列和getPackageInfoNoCheck;

简单查看源代码发现,getPackageInfo除了获取包的信息,还检查了包的一些组件;

为了绕过这些验证,我们选择使用getPackageInfoNoCheck获取LoadedApk信息。

5.1 构建插件LoadedApk对象

我们这一步的目的很明确,通过getPackageInfoNoCheck函数创建出我们需要的LoadedApk对象,以供接下来使用。

这个函数的签名如下:

public final LoadedApk getPackageInfoNoCheck(ApplicationInfo ai,
            CompatibilityInfo compatInfo) {

因此,为了调用这个函数,我们需要构造两个参数。其一是ApplicationInfo,其二是CompatibilityInfo;

第二个参数顾名思义,代表这个App的兼容性信息,比如targetSDK版本等等,这里我们只需要提取出app的信息,

因此直接使用默认的兼容性即可;在CompatibilityInfo类里面有一个公有字段

DEFAULT_COMPATIBILITY_INFO代表默认兼容性信息;因此,我们的首要目标是获取这个ApplicationInfo信息。

5.2 构建插件ApplicationInfo信息

我们首先看看ApplicationInfo代表什么,这个类的文档说的很清楚:

Information you can retrieve about aparticular application. This corresponds to information collected from theAndroidManifest.xml’s <application> tag.

也就是说,这个类就是AndroidManifest.xml里面的这个标签下面的信息;

这个AndroidManifest.xml无疑是一个标准的xml文件,因此我们完全可以自己使用parse来解析这个信息。

那么,系统

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值