android启动Service有两种方式,一种是startService,还有一种是bindService,关于startService的启动流程可以参照https://www.jianshu.com/p/fd31917c518a ,bindService的运行流程如下所示:
![img_d8f56baea006d592d990585b22bd517f.png](https://yqfile.alicdn.com/img_d8f56baea006d592d990585b22bd517f.png?x-oss-process=image/resize,w_1400/format,webp)
1、Activity.bindService-->ContextImpl.bindService-->ContextImpl.bindServiceCommon
![img_094283902995e0e25e62ab539ed1e4c0.png](https://yqfile.alicdn.com/img_094283902995e0e25e62ab539ed1e4c0.png?x-oss-process=image/resize,w_1400/format,webp)
ContextImpl.bindServiceCommon首先调用mPackageInfo.getServiceDispatcher获取IServiceConnection对象,IServiceConnection是个Binder类型,具体内容如下:
![img_931f2303ae39ebdbec74a42821ccba21.png](https://yqfile.alicdn.com/img_931f2303ae39ebdbec74a42821ccba21.png?x-oss-process=image/resize,w_1400/format,webp)
mPackageInfo.getServiceDispatcher中先创建了ServiceDispatcher,并传入bindService调用方的ServiceConnection,返回调用ServiceDispatcher.getIServiceConnection:
![img_dd3062a26cca50dc2c42425ab7d0260a.png](https://yqfile.alicdn.com/img_dd3062a26cca50dc2c42425ab7d0260a.png?x-oss-process=image/resize,w_1400/format,webp)
其中mIServiceConnection是在ServiceDispatcher中赋值的:
![img_fe2462537f45f2384702f3eb3138664d.png](https://yqfile.alicdn.com/img_fe2462537f45f2384702f3eb3138664d.png?x-oss-process=image/resize,w_1400/format,webp)
mIServiceConnection的实现类是InnerConnection:
![img_359c28f628a7ca11664daac148dbd839.png](https://yqfile.alicdn.com/img_359c28f628a7ca11664daac148dbd839.png?x-oss-process=image/resize,w_1400/format,webp)
InnerConnection是Binder Service端的存根,返回给Binder Client端进行跨进程调用的,在bindService的时候将InnerConnection对象传送给AMS,这样AMS就可以跨进程调用bindService调用方的ServiceConnection。这一点和ApplicationThread以及广播的IIntentReceiver如出一辙。
创建完IServiceConnection后就调用AMS的bindService并传入IServiceConnection对象。
2、AMS.bindService-->ActiveServices.bindServiceLocked-->ActiveServices.requestServiceBindingLocked
在bindServiceLocked函数中,判断是否是AUTO_CREATE,如果是,就调用bringUpServiceLocked启动Service并触发Service.onCreate,然后再requestServiceBindingLocked:
![img_351ffca44778795886e368b388435ee2.png](https://yqfile.alicdn.com/img_351ffca44778795886e368b388435ee2.png?x-oss-process=image/resize,w_1400/format,webp)
requestServiceBindingLocked会调用ApplicationThread.scheduleBindService
3、ApplicationThread.scheduleBindService-->ActivityThread.handleBindService
![img_0bd5517f8752f5d88d0ee0963697def3.png](https://yqfile.alicdn.com/img_0bd5517f8752f5d88d0ee0963697def3.png?x-oss-process=image/resize,w_1400/format,webp)
ActivityThread.handleBindService首先从mServices中取出要Binde的service(在第二步bindServiceLocked函数中会创建Service对象并保存),取到之后就调用s.onBind方法获取当前Service返回给远程bindService调用方的binder对象,最后调用AMS.plublishService,并将s.onBind传过去,该值最终会传给bindService的ServiceConnection.onServiceConnected中。
4、AMS.publishService-->ActiveServices.publishServiceLocked
![img_4da1ea79567a56cf4bec30f2926cb51b.png](https://yqfile.alicdn.com/img_4da1ea79567a56cf4bec30f2926cb51b.png?x-oss-process=image/resize,w_1400/format,webp)
ActiveServices.publishServiceLocked中调用了c.conn.connected,c.conn就是第一步中创建的InnerConnection对象,c.conn.connected会调用ServiceDispatcher.doConnected:
![img_b55b48a1e759bebc0d35193dcbaf1b2b.png](https://yqfile.alicdn.com/img_b55b48a1e759bebc0d35193dcbaf1b2b.png?x-oss-process=image/resize,w_1400/format,webp)
ServiceDispatcher.doConnected最终调用了ServiceConnection.onServiceConnectioned,并传入第三步中s.onBind的返回值。
5、bindService的调用以AMS.serviceDoneExecuting收尾。
在理解了startService和bindService的运行流程后,似乎对Service如何插件化还没任何思路。下面说下VirtualApk是如何实现的吧。
VitualApk在实现Service插件化的时候依然是采用的宿主占坑的方案,通过在宿主实现占坑的LocalService和RemoteService,
![img_2109d8de87ca0626eaecec16a662648d.png](https://yqfile.alicdn.com/img_2109d8de87ca0626eaecec16a662648d.png?x-oss-process=image/resize,w_1400/format,webp)
通过hook掉AMS启动Service相关的方法,如果发现是启动插件的Service,就将目标Service转化为宿主占坑的Service,再由宿主占坑Service实现代理转发,在宿主Service中反射加载插件Service的实例,并调用其对对应的方法,这里以LocalService为例,描述下整个流程:
1、Hook掉AMS的startService bindService等函数
![img_b17b470516ff6b5ce9a9f9fb2126c269.png](https://yqfile.alicdn.com/img_b17b470516ff6b5ce9a9f9fb2126c269.png?x-oss-process=image/resize,w_1400/format,webp)
hookSystemService会替换掉当前进程的AMS本地代理,实现了自己的ActivityManagerProxy
![img_c71a6ea1923d95eda9768648e80c8f5e.png](https://yqfile.alicdn.com/img_c71a6ea1923d95eda9768648e80c8f5e.png?x-oss-process=image/resize,w_1400/format,webp)
ActivityManagerProxy hook调用Service相关的方法,这里以startService为例:
![img_ea88feb4670a764be9fb14873a4362e9.png](https://yqfile.alicdn.com/img_ea88feb4670a764be9fb14873a4362e9.png?x-oss-process=image/resize,w_1400/format,webp)
startService中会调用startDelegateServiceForTarget:
![img_19c5c0d42d1ace0fb9d68deadb7d3a64.png](https://yqfile.alicdn.com/img_19c5c0d42d1ace0fb9d68deadb7d3a64.png?x-oss-process=image/resize,w_1400/format,webp)
其中wapperTargetIntent将启动插件Service的Intent转为启动宿主占坑Service:
![img_3f978d89ead1f9d5d24dc6761455ba80.png](https://yqfile.alicdn.com/img_3f978d89ead1f9d5d24dc6761455ba80.png?x-oss-process=image/resize,w_1400/format,webp)
2、LocalService的处理
第一步将启动插件Service的Intent转为了启动宿主占坑的LocalService,LocalService中会实现代理转发。LocalService.onStartCommand中有如下代码:
![img_b95daff7f0dd67ad42fad3e00ef2ddb7.png](https://yqfile.alicdn.com/img_b95daff7f0dd67ad42fad3e00ef2ddb7.png?x-oss-process=image/resize,w_1400/format,webp)
LocalService.onStartCommand首先反射创建插件Service对象,返回反射调用了其attach方法,最后调用了Service.onCreate,这样就完成了startService启动插件Service的插件化。
其他Service方法的插件化类似,可自行分析。