运维开发网

插件化入门篇-如何启动一个未注册过的Activity

运维开发网 https://www.qedev.com 2020-12-25 08:23 出处:51CTO 作者:mb5fe18fab305a5
几乎所有的插件化都会要的一个需求,启动一个未注册的Activiy,即加载插件包中的Activity,并且主应用并不知道插件应用中会有什么Activity,这是各个插件化框架主力解决的问题之一。今天我们学习一下占坑式插件化框架的启动Activity原理。关于动态代理的知识,了解过Retrofit的源码的或者看过Java设计模式之代理模式的高级使用的,应该都了解了。本章不做介绍,主介绍hook+反射。

几乎所有的插件化都会要的一个需求,启动一个未注册的Activiy,即加载插件包中的Activity,并且主应用并不知道插件应用中会有什么Activity,这是各个插件化框架主力解决的问题之一。

今天我们学习一下占坑式插件化框架的启动Activity原理。

关于动态代理的知识,了解过Retrofit的源码的或者看过Java设计模式之代理模式的高级使用的,应该都了解了。本章不做介绍,主介绍hook+反射。

Hook是什么?

Hook直白点说就是拦截方法,自己对其参数等进行修改,或者替换返回值,达到自己不可告人的目的的一件事。

寻找Hook点

对于启动Activity,老实说光startActivity便有很多要说,很多文章会带着你一直追到ActivityManagerService中的若干个方法,最后再调用本地的ActivityThread里面的方法去启动本进程的Activity

所以光上面的流程我们看出,我们把要启动的Activity信息发给AMS,其做了各种检查各种操作后真正让Activity启动的还是我们的ActivityThread

startActivity流程

我们startActivitycontext的方法,去找Context实现类class ContextImpl extends Context。

看到最后调用的是mMainThread.getInstrumentation().execStartActivitiesAsUser方法,不用着急,直接ctrl鼠标左击进去。是Instrumentation类。

这边我们看到了,是调用ActivityManagerNative的方法启动activity了。进去这个类我们只能看到一堆的binder通信,调用AMS的方法,不过此时我们不用关心了,因为我们知道接下来是

AMS的事情。AMS是活在另一个PID的玩意儿,我们只关心我们自己的pid,另一个进程的东西我们没权限干坏事。

不过这边我们需要注意,ActivityManagerNative居然是个单类,那么我们hook它会安全很多,毕竟这个对象是单类。

说是说AMS的事情不用关心,但是我们得关心AMS什么时候回调回来,让我们启动Activity。

ActivityThread看,一搜里面有个handleLaunchActivity方法,是在Handler里面被调用的,而且ActivityThread也是我们喜欢的对象,因为这个对象存在于整个应用生命周期中。

看了这么多,我们可算是知道启动Activity的入口和出口了,下面我们需要进行欺骗。

实现欺骗

欺骗系统就欺骗两个地方,我们在AndroidManifest里面申明一个假Activity,然后在启动真实Activity的地方,将Intent里面的Activity替换成我们已经注册过的。再在ActivityThread launch Activity的时候,替换成我们需要启动的便实现了启动一个未注册过的Activity的效果。

代码实现

  • 写一个占坑Activity,在AndroidManifest注册

       /**
         * 占坑专用
         */
        public class TmpActivity extends Activity {            

           @Override            protected void onCreate(Bundle savedInstanceState) {

               super.onCreate(savedInstanceState);                setContentView(R.layout.activity_tmp);            }        }

<!--占坑专用Activity-->
        <activity android:name=".TmpActivity"/>
  • 在attachBaseContext中欺骗应用

插件化入门篇-如何启动一个未注册过的Activity

插件化入门篇-如何启动一个未注册过的Activity

插件化入门篇-如何启动一个未注册过的Activity

插件化入门篇-如何启动一个未注册过的Activity

插件化入门篇-如何启动一个未注册过的Activity

上面的代码,我们先反射拿到ActivityManagerNative,然后动态代理IActivityManager,Hook其startActivity方法,在里面替换掉intent,并将真实的Intent存放在假Intent的参数里面。

在系统最后调用打开假Intent的时候,我们从Intent中取出参数,并打开真正想打开的Activity

打开Activity

我们和正常使用一样,startActivity就能打开我们未注册的Activity了。

插件化入门篇-如何启动一个未注册过的Activity

Demo路径:https://github.com/Jerey-Jobs/AppPluginDemos

总结

上面只是一个Demo,不能支持support包的AppCompatActivity,真正的完整的插件化库任务是艰巨的!

还要支持其他组件,都是很麻烦的事情。

0

精彩评论

暂无评论...
验证码 换一张
取 消