因为Activity的特殊性,activity的class被classLoader加载之后是可以当普通类使用了,但是生命周期需要系统回调。而且activity的启动过程比较复杂,不是一个简单的类加载和反射的过程。
为实现Activity的生命周期,实现方案都需要预先在宿主中占位,插件化技术发展到现在,为了轻量化,目前主流的实现方案有两种:
- 替换Class loader
- 替换Instrumentation
Activity启动过程
要实现这两种方案,先要了解Activity的启动过程
- AMS: 即ActivityManagerServices,服务端对象,负责系统中所有Activity的生命周期
- ActivityThread:App的入口,当开启App之后,会调用main()开始运行,开启消息循环队列。就是主线程。
与ActivityManagerServices配合,一起完成Activity的管理工作。 - Instrumentation: 应用内单实例对象,负责Activity的创建和暂停
- ApplicationThread:负责ActivityManagerService与ActivityThread之间的交互。在ActivityManagerService需要管理相关Application中的Activity的生命周期时,通过ApplicationThread的代理对象与ActivityThread通讯
- ApplicationThreadProxy: ApplicationThread在服务器端的代理,负责和客户端的ApplicationThread通讯。AMS就是通过该代理与ActivityThread进行通信的
- ActivityStack:Activity在AMS的栈管理,用来记录已经启动的Activity的先后关系,状态信息等。通过ActivityStack决定是否需要启动新的进程
启动流程简述
- 先通过Instrumentation检查对应的Activity是否已经启动,若已经启动切符合条件则直接返回。没有在调用AMS去启动activity
- AMS调用ActivityStarter启动Activity。ActivityStarter先解析Intent中Activity的信息。查询系统中是否有符合要求的Activity
- 使用合适的ActivityStack和 launch flags 来启动 Activity, 如果存在可以直接恢复 Activity,则恢复,否则重新启动 Activity
- 如果此时Activity所在的App未启动,则先创建对应的App进程
- 若要启动新的Activity,AMS会通过binder调用App进程,使用 ActivityThread 去执行启动,
- Instrumentation对过反射生成Activity的实例
- 使用handler来调用新生成的Activity的生命周期
替换Class loader
实现过程
- 自定义一个PathClassLoader,App启动时将自定义的ClassLoader替换系统的ClassLoader
- 解析启动插件Activity的intent,找到插件中对应的Activity class
- 分配与要启动的Activity的启动方式一致的坑位Activity,并保持两个Activity的关联
- 让系统启动坑位的Activity, 系统会使用替换过的ClassLoader加载坑位的Activity
- 替换过的ClassLoader启动坑位的Activity时,通过对应的关联找到对应的插件中的activity,
找到后加载并返回 - android系统拿到的Activity就是插件中的activity, 然后调用它的生命周期
替换Instrumentation
这个方案比较简单和轻量,由于activity的启动和反射都是在Instrumentation中进行的,所以只hook启动和反射生成实例的程就可以将占位的activity替换为插件中的Activity
实现过程
- 封装一个Instrumentation,重写启动Activity的方法
- 将启动的插件中的Activity替换为占位的activity
- 重写Instrumentation的newActivity方法,使用插件的class loader 反射生成插件的activity
- 然后将封装的Instrumentation替换掉宿主中的Instrumentation
这样宿主启动的acticity最终被替换成了插件中的activity,生命周期完全由系统管理。
但是由于启动方式多样性,所以占坑的时候需要埋入比较多的占坑Acttivity来应对不同的启动方式
这个方案的过程比较简单,而且hook的点很少,所以很轻量