Jimmy Chen

A Programmer

(原创)ServiceManager.addService流程学习

  最近在公司有听到同事做的一个需求。就是一个非系统应用(不使用系统签名),通过额外的方法,将自身一个AIDL service的binder句柄通过ServiceManager.addService接口注册到ServiceManager中。那么其他应用就能通过ServiceManager.getService来获取到该service提供的binder句柄,从而进行跨进程调用了。

  首先这里定一个调调,那就是我们不评判这样实现是否有问题。我们之关注技术,这里我们想关注的点有:1)ServiceManager.addService的流程;2)这种方式添加binder句柄到ServiceManager后,代码是否运行在system_server进程。下面所有分析的代码都是基于Android11_R17进行分析。

0. ServiceManager.addService流程

ServiceManager.addService的流程如上面代码所示,我们一般调用的都是两个参数的addService方法,这个方法然后会继续调用四个参数的重构方法。四参的方法内部首先通过getIServiceManager获取service_manager中的代理Proxy,代码如下:

1 getIServiceManager获取service_manager binder代理

1.1 BinderInternal.getContextObject()

BinderInternal.getContextObject() 是一个native方法,实现在android_util_Binder.cpp文件中

首先首先调用了ProcessState::getContextObject方法,然后通过javaObjectForIBinder方法将native层的binder对象封装成Java层的binder对象并返回给调用者。ProcessState::getContextObject方法内部再通过getStrongProxyForHandle(0)找到0号的binder对象,0号的binder对象就是service_manager了。

OK,BinderInternal.getContextObject()过程中涉及的方法都已经介绍完毕,从最终的结果来看,ProcessState::getStrongProxyForHandle方法最后返回的是0号BpBinder。Binder.allowBlocking的作用是将BinderProxy的sWarnOnBlocking值置为false,这里我们就略过这部分代码,所以最终传给ServiceManagerNative.asInterface的就是一个handle为0的BpBinder了。后面我们继续看下一步ServiceManagerNative.asInterface方法的实现

1.2 ServiceManagerNative.asInterface

ServiceManagerNative.asInterface的实现总体看还是比较简单的

asInterface方法内部直接创建的是ServiceManagerProxyServiceManagerProxy内部首先是保存这个service_manager的BpBinder句柄到mRemote成员变量中;然后通过IServiceManager.Stub.asInterface将BpBinder句柄转换为IServiceManager对象,并将其保存到mServiceManager成员变量中。源码中IServiceManager是一个AIDL文件,在 源码编译的时候会将其转换为Java和C++代码。有兴趣的同学可以尝试反编译框架的代码,就可以看到IServiceManager反编译之后的实现了。后面有遇到对应的实现,我们再将反编译代码贴出来,这里我们只需要知道IServiceManager.Stub.asInterface调用完后,返回的就是一个封装成ServiceManagerProxy类型的servcie_manager代理对象。

2. addService流程

上面第1部的一整套流程之后,通过分析getIServiceManager我们获取到的是封装成ServiceManagerProxy类型的servcie_manager代理对象,然后就是通过调用getIServiceManager().addService(name, service, allowIsolated, dum pPriority);进行addService操作。ServiceManagerProxy是如何进行addService操作的

可以看到,这里是直接调用成员变量mServiceManager的addService方法,如第一部分我们讨论过的,mServiceManager是IServiceManager的代理对象,IServiceManager是由AIDL编译而来,我们下面直接看AIDL编译后的addService代码

制造binder通信所需要的data parcel并填入对应的数据,这里重要的部分是调用了writeStrongBinder。这部分代码我们简单的跟踪下,writeStrongBinder会通过JNI调用到native层Parcel.cpp的同名方法,而Parcel.cpp的writeStrongBinder会调用到flattenBinder对传入的Binder对象进行扁平化操作,我们就从flattenBinder开始进行分析

这段代码中,需要判断传进来的binder对象是BpBinder还是BBinder,然后如果是binder对象,就将其保存到flat_binder_object的binder成员变量中,如果是binder句柄,即binder代理对象,这将句柄保存到flat_binder_object的handle成员变量中。最后再通过finishFlattenBinder调用完成数据的扁平化操作。

OK,我们回到AIDL部分的addService操作,addService完成的Parcel数据的相关操作后,最后还是通过transact方法将调用传递到service_manager中。如上面展示,在传递的过程中有对数据进行flattenBinder操作,那么肯定也会对数据进行unflattenBinder操作,unflattenBinder的代码这里就不分析了,有兴趣的同学自行查看。紧接着我们看service_manager的addService是如何实现的

从上面可以看到,我们最后将传入的binder和service name构造出一个struct Service对象,并保存到mNameToService中,到这里我们的addService操作就完成了,可以看到这整个过程中,其实是没有进行进程拉起操作的。所以可以肯定的是如果应用将自身的binder服务句柄通过其他方法添加到service_manager中,其服务也只是运行在应用自身的进程。

其实我们额外再留意运行在service_manager中的服务,例如AMS、PMS等服务,我们会发现,这些服务都是service_manager在启动的时候,通过startBootstrapServicesstartCoreServices等方法将AMS、PMS这些服务自己拉起,所以这些服务才会运行在service_manager中。

OK,这一篇分析完成。题外话,这一篇其实还是写了挺长时间的,主要是这个system_server的代码架构和之前Android O的代码架构相比,变化实在是稍微有点大了。

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据

%d 博主赞过: