VirtualApk源码分析- service插件化

简介: android启动Service有两种方式,一种是startService,还有一种是bindService,关于startService的启动流程可以参照https://www.

android启动Service有两种方式,一种是startService,还有一种是bindService,关于startService的启动流程可以参照https://www.jianshu.com/p/fd31917c518a ,bindService的运行流程如下所示:

img_d8f56baea006d592d990585b22bd517f.png
bindService流程

1、Activity.bindService-->ContextImpl.bindService-->ContextImpl.bindServiceCommon

img_094283902995e0e25e62ab539ed1e4c0.png
ContextImpl.bindServiceCommon

ContextImpl.bindServiceCommon首先调用mPackageInfo.getServiceDispatcher获取IServiceConnection对象,IServiceConnection是个Binder类型,具体内容如下:

img_931f2303ae39ebdbec74a42821ccba21.png
mPackageInfo.getServiceDispatcher

mPackageInfo.getServiceDispatcher中先创建了ServiceDispatcher,并传入bindService调用方的ServiceConnection,返回调用ServiceDispatcher.getIServiceConnection:

img_dd3062a26cca50dc2c42425ab7d0260a.png
ServiceDispatcher.getIServiceConnection

其中mIServiceConnection是在ServiceDispatcher中赋值的:

img_fe2462537f45f2384702f3eb3138664d.png
ServiceDispatcher构造函数

mIServiceConnection的实现类是InnerConnection:

img_359c28f628a7ca11664daac148dbd839.png
InnerConnection

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
requestServiceBindingLocked

requestServiceBindingLocked会调用ApplicationThread.scheduleBindService

3、ApplicationThread.scheduleBindService-->ActivityThread.handleBindService

img_0bd5517f8752f5d88d0ee0963697def3.png
ActivityThread.handleBindService

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
ActiveServices.publishServiceLocked

ActiveServices.publishServiceLocked中调用了c.conn.connected,c.conn就是第一步中创建的InnerConnection对象,c.conn.connected会调用ServiceDispatcher.doConnected:

img_b55b48a1e759bebc0d35193dcbaf1b2b.png
ServiceDispatcher.doConnected

ServiceDispatcher.doConnected最终调用了ServiceConnection.onServiceConnectioned,并传入第三步中s.onBind的返回值。

5、bindService的调用以AMS.serviceDoneExecuting收尾。

在理解了startService和bindService的运行流程后,似乎对Service如何插件化还没任何思路。下面说下VirtualApk是如何实现的吧。

VitualApk在实现Service插件化的时候依然是采用的宿主占坑的方案,通过在宿主实现占坑的LocalService和RemoteService,

img_2109d8de87ca0626eaecec16a662648d.png
占坑Service

通过hook掉AMS启动Service相关的方法,如果发现是启动插件的Service,就将目标Service转化为宿主占坑的Service,再由宿主占坑Service实现代理转发,在宿主Service中反射加载插件Service的实例,并调用其对对应的方法,这里以LocalService为例,描述下整个流程:

1、Hook掉AMS的startService bindService等函数

img_b17b470516ff6b5ce9a9f9fb2126c269.png
PulginManager.hookSystemServices

hookSystemService会替换掉当前进程的AMS本地代理,实现了自己的ActivityManagerProxy

img_c71a6ea1923d95eda9768648e80c8f5e.png
ActivityManagerProxy.invoke

ActivityManagerProxy hook调用Service相关的方法,这里以startService为例:

img_ea88feb4670a764be9fb14873a4362e9.png
ActivityManagerProxy .startService

startService中会调用startDelegateServiceForTarget:

img_19c5c0d42d1ace0fb9d68deadb7d3a64.png
startDelegateServiceForTarget

其中wapperTargetIntent将启动插件Service的Intent转为启动宿主占坑Service:

img_3f978d89ead1f9d5d24dc6761455ba80.png
wapperTargetIntent

2、LocalService的处理

第一步将启动插件Service的Intent转为了启动宿主占坑的LocalService,LocalService中会实现代理转发。LocalService.onStartCommand中有如下代码:

img_b95daff7f0dd67ad42fad3e00ef2ddb7.png
LocalService.onStartCommand

LocalService.onStartCommand首先反射创建插件Service对象,返回反射调用了其attach方法,最后调用了Service.onCreate,这样就完成了startService启动插件Service的插件化。

其他Service方法的插件化类似,可自行分析。

目录
相关文章
|
存储 缓存 编译器
探索 Jetpack Compose 内核:深入 SlotTable 系统
探索 Jetpack Compose 内核:深入 SlotTable 系统
596 1
|
SQL 存储 缓存
PG内核解读-第2节PostgreSQL体系结构
本文整理自阿里云数据库开源社区Maintainer于巍(花名漠雪),在PostgreSQL数据库内核解读系列的分享。本篇内容主要分为三个部分: 1. PostgreSQL系统表 2. PostgreSQL初始化、启动、查询流程 3. PostgreSQL辅助进程
PG内核解读-第2节PostgreSQL体系结构
|
存储 弹性计算 固态存储
阿里云服务器按月租用价格是多少,月付收费标准与活动价格参考
阿里云服务器月付租用价格是多少?阿里云服务器既可以月租也可以按年租用,按月可选的时长有1个月到10个月,通常选择较多的是1个月、3个月、6个月时长,目前按月租用价格有经济型e实例4核16G配置10M带宽100G ESSD Entry云盘,月租优惠价70元1个月、210元3个月,如果选择8核32G配置的月付优惠价是160元1个月、480元3个月。本文将详细介绍阿里云服务器的月付收费标准及当前活动价格,帮助您更好地了解在阿里云服务器月付租用价格情况。
|
资源调度 JavaScript
Vue2拖拽插件(vuedraggable)
这篇文章介绍了如何在Vue 3框架中使用`vuedraggable`插件来实现拖拽功能,并提供了插件的安装、配置和事件处理的示例。
1357 1
Vue2拖拽插件(vuedraggable)
|
SQL 存储 数据库
SQL学习一:ACID四个特性,CURD基本操作,常用关键字,常用聚合函数,五个约束,综合题
这篇文章是关于SQL基础知识的全面介绍,包括ACID特性、CURD操作、常用关键字、聚合函数、约束以及索引的创建和使用,并通过综合题目来巩固学习。
498 1
|
网络协议 NoSQL 应用服务中间件
如何在 asyncio 中使用 socket
如何在 asyncio 中使用 socket
242 1
|
关系型数据库 MySQL API
Python管理系统源代码
本文介绍了多种基于Python和相关技术的管理系统源代码,包括学生信息管理、图书管理、ERP、异常管理、考试系统等。提供了64个源代码供下载,适用于不同场景和个人项目需求。下载链接:https://pan.baidu.com/s/1hXPLbKHMpBDhlFVv1kdMxA?pwd=8888,提取码:8888。欢迎使用和支持。
420 3
|
人工智能
从浅到深研究矩阵的特征值、特征向量
从浅到深研究矩阵的特征值、特征向量
662 0
|
SQL 存储 关系型数据库
SQL安装指南:一步步教你如何安装并配置SQL数据库
展望未来,随着技术的不断进步和应用场景的不断拓展,SQL数据库将继续发挥重要作用。同时,我们也需要不断学习和掌握新的数据库技术和工具,以适应不断变化的市场需求和技术挑战。希望本文能为你提供一个良好的起点,帮助你在SQL数据库的学习和实践之路上取得更大的进步。
|
机器学习/深度学习 并行计算 关系型数据库
【RetNet】论文解读:Retentive Network: A Successor to Transformer for Large Language Models
【RetNet】论文解读:Retentive Network: A Successor to Transformer for Large Language Models
591 1