要解决这个问题,首先回顾一下启动一个新的Activity的流程:
- 要启动ActivityB,将要启动的ActivityB信息告诉AMS;
- AMS收到信息后,记录下ActivityB的相关信息,同时检查Manifest中是否已经注册了ActivityB,如果一切正常,则回传消息给ActivityThread:我接收到了!你可以paused了!
- ActivityA进入Paused状态,再告诉AMS:我已经休眠了!
- AMS开始启动的相关准备操作,查看ActivityA和ActivityB是否在同一进程,然后取出之前保存的ActivityB的相关信息,发送给ActivityThread,说:你创建并启动ActivityB。
- ActivityThread接收到信息之后,通过Instrumentation反射创建ActivityB,并且启动ActivityB。
要启动没有在Manifest中声明的Activity有一个难点:
要怎样规避上述步骤2中的AMS检查Manifest中是否有注册?
对于这个问题,可能有的会说:hook AMS可以么? 答案肯定是不行的,因为AMS如果可以进行Hook,那么Android系统早就崩溃了,要知道所有App底层都是公用的AMS。 既然这样,只能从上层动手,也就是上面的步骤中想解决办法。
“欺骗”AMS方案
对于“欺骗”AMS方案,可以这样理解,因为AMS是被动接收数据的,也就是说AMS负责校验ActivityThread发送过来的数据,想一下:如果我发送过来的确确实实是已经在Manifest中已经注册过的ActivityC呢? 然后我把ActivityB的相关信息都保存在ActivityC的启动信息中,这样AMS是不是就被骗了?答案是肯定的!
上述步骤1,就顺利的执行了,等到了步骤5, 我们又可以做手脚了,我们通过hook,拦截Instrumentation的启动ActivityC的方法,改为创建ActivityB,也就是偷梁换柱。
说白了我们“欺骗”AMS的方案就两步骤:
- 拦截上述步骤1,把要启动的ActivityB的相关信息更换为已经在Manifest中注册的ActivityC,并且把ActivityB相关信息保存起来,塞入ActivityC的Intent中,因为