我们先来看下Android常规Activity的启动流程
如何评价360的Android插件化框架RePlugin? - 知乎
1、调用Context.startActivity -> ActivityManagerProxy -> AMS, AMS通过Intent从PMS拿到ActivityInfo并创建ActivityRecord和token放入前台ActivityStack,接着按需启动Activity所属进程
2、进程启动后,马上执行入口ActivityThread.main并调用attachApplication将启动信息反馈到AMS,AMS通过pid找到对应的ProcessRecord并更新其数据
3、从前台ActivityStack中拿到栈顶的ActivityRecord,如果其proecssrecord为null,并且uid和processname跟新创建的ProcessRecord一致,则正式调用app.thread.scheduleLaunchActivity
4、ActivityThread在scheduleLaunchActivity中创建ActivityClientRecord,用于跟AMS中的ActivityRecord对应,ActivityClientRecord最重要的两个字段是token和activityinfo,token用于关联ActivityRecord,activityinfo则包含activity的描述和所属包等信息
5、在scheduleLaunchActivity内部接着发送LAUNCH_ACTIVITY message到mH这个handler,mH收到LAUNCH_ACTIVITY message后执行handleLaunchActivity
请求阶段:
ActivityManagerProxy是ActivityManagerService在app进程中的Binder代理对象。调用ActivityManagerProxy.startActivity()最后会调用ActivityManagerService.startActivity()。这样请求就到了ActivityManagerService
响应阶段:
在不考虑多进程的情况下,Activity的启动过程是一个Binder双向通信的过程。AMS要主动与app进程通信要依靠请求启动Activity阶段传过来的IBinder对象,这个IBinder对象就是上面介绍过的Instrumentation.execStartActivity()中的 whoThread对象,它实际上是一个ApplicationThreadProxy对象,用来和ApplicationThread通信。AMS通知app进程启动Activity是通过调用ApplicationThreadProxy.scheduleLaunchActivity()完成的。根据Binder通信,ApplicationThread.scheduleLaunchActivity()会被调用。
- scheduleLaunchActivity()将从AMS中传过来的参数封装成ActivityClientRecord对象,然后将消息发送给mH,mH是一个Handler对象。
- H是ActivityThread的内部类,继承自Handler,它在收到LAUNCH_ACTIVITY的消息后,会调用ActivityThread.handlerLaunchActivity()。
- handleLaunchActivity()主要调用了两个方法:performLaunchActivity()和handleResumeActivity()。performLaunchActivity()会完成Activity的创建,以及调用Activity的onCreate()、onStart()等方法。handleResumeActivity()会完成Activity.onResume()的调用。
假如在插件中有一个未在AndroidManifest.xml注册的TargetActivity,我们想启动它,可以分为三步。Activity启动流程和插件化原理 - 掘金
- 在AndroidManifest.xml中预先注册一个我们项目中没有的Activity,例如ProxyActivity。我们把这种行为称为插桩。
- 在请求启动Activity阶段,我们把TargetActivity替换成AndroidManifest中预先注册的ProxyActivity。
- 在AMS响应阶段,Activity实例产生之前,我们再做一个完全相反的动作。即把响应信息中要启动的ProxyActivity替换回TargetActivity。
第一步十分简单,没什么好说的。要实现第二步和第三步就需要用到Activity启动流程的知识了。 在Activity启动流程中,Instrumentation无论在请求阶段还是响应阶段都扮演着重要的角色。在请求阶段Instrumentation.execStartActivity()会被调用,而在响应阶段Instrumentation.newActivity()会被调用。因此如果我们可以Hook Instrumentation,那么我们就可以在execStartActivity()和newActivity()分别完成第二步和第三步中的功能。
最终目的:Hook Instrumentation
1、通过反射替换ActivitThread的Instrumentation
2、Instrumentation.execStartActivity()执行前将我们要启动的Activity替换成预注册的ProxyActivity
3、在Instrumentation.newActivity()执行前将预注册的ProxyActivity替换回我们要启动的Activity