Android 跨进程通信-Binder机制之ServiceManager对系统Service的管理
Posted 好人静
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 跨进程通信-Binder机制之ServiceManager对系统Service的管理相关的知识,希望对你有一定的参考价值。
目录
二 ServiceManager进程跨进程实现addService()( Framework层)
1.ServiceManager进程的跨进程的具体实现类为ServiceManagerNative类
2.在实现system_server进程调用ServiceManager进程的相关接口方法
(1)system_server进程通过ServiceManagerNative.asInterface()来获取到Client进程的BinderProxy;
(2)system_server进程通过BinderProxy.transact()将数据通过jni传递到BpBinder.transact()
(3)BpBinder通过Binder线程IPCThreadState将数据发送给Binder驱动
(4)Binder驱动将数据发送给ServiceManager进程来处理消息
三 ServiceManager之getService()( Framework层)
2.Binder.allowBlocking(getIServiceManager().getService(name))
四 ServiceManager在Native层管理系统服务
前言
在Android 跨进程通信-(二)Binder机制之ServiceManager主要是总结了ServiceManager进程是怎么和Binder驱动进行通信的。在Android 跨进程通信-(八)AIDL中的代理模式之源码分析中二 ServiceManager跨进程通信实现主要从源码角度总结了ServiceManager进程与其他进程进行通信的相关类。那么ServiceManager是用来管理系统Service的,那么到底是怎么完成系统Service的注册和查询呢?
一 ServiceManager进程
ServiceManager进程是有init进程创建出来的。在Zygote进程创建之前,就会把该ServiceManager进程创建并启动起来。在ServcieManager进程创建启动的时候,会通过service_manager.c中的main()完成:
- (1)获取Binder驱动的设备文件"/dev/binder"的文件描述符,完成内存映射;
- (2)通知Binder驱动该进程为ServiceManager进程;
- (3)同时开启循环,来读取Client和Server进程发出注册和查询Service的请求;
- (4)ServiceManager进程通过ioctl与Binder驱动进程传递数据。
二 ServiceManager进程跨进程实现addService()( Framework层)
当Zygote进程fork出system_server进程,system_server进程在进行功能加载的时候,会调用到ServiceManager.addService(),将该系统Service添加到ServiceManager进行管理。ServiceManager封装system_server进程跨进程访问ServiceManager进程的相关逻辑,对于system_server进程只需调用ServiceManager的相关方法即可。
1.ServiceManager进程的跨进程的具体实现类为ServiceManagerNative类
- 1)IServiceMananger为公共接口类,提供ServiceManager功能的标准;
- 2)ServiceManagerNative为ServiceManager进程的功能在本地的实现。继承Binder,为ServiceManager进程访问Binder驱动的操作类;
- 3)ServiceManagerNative.ServiceManagerProxy为ServiceManagerNative的代理对象,为system_server进程访问Binder驱动的操作类。
2.在实现system_server进程调用ServiceManager进程的相关接口方法
在完成这个两个进程的IPC,主要经历下面四个步骤,这四个过程和应用层的跨进程Service也有一些不一样的地方。
(1)system_server进程通过ServiceManagerNative.asInterface()来获取到Client进程的BinderProxy;
该过程已经封装到ServiceManger类。
这里体现了与在应用层的跨进程Service的第一个不同点:Client进程的BinderProxy的获取方式不同。
在Android 跨进程通信-(八)AIDL中的代理模式之源码分析中的3.与应用层的mRemote的区别中也简单的提到过这点不同。
- 1)在应用层的跨进程Service:该BinderProxy是有Service通过onBind()直接将Server进程的Stub返回;
- 2)在ServiceManager:是通过BinderInternal.getContextObject()来获取handle为0(即ServiceManager进程)的BpBinder,经过Binder.allowBlocking( )转换成java可以识别的BinderProxy。
在Android 跨进程通信-(八)AIDL中的代理模式之源码分析中的4.Binder.allowBlocking()提到在BinderInternal.getContextObject()通过jni调用到ProcessState::getStrongProxyForHandle(0),在该方法中主要就是通过new BpBinder(0)返回给该方法。在BpBinder中代码如下:
BpBinder::BpBinder(int32_t handle)
: mHandle(handle)
, mAlive(1)
, mObitsSent(0)
, mObituaries(NULL)
{
ALOGV("Creating BpBinder %p handle %d\\n", this, mHandle);
extendObjectLifetime(OBJECT_LIFETIME_WEAK);
IPCThreadState::self()->incWeakHandle(handle);
}
也就是返回一个handle为0的IPCThreadState ,这个IPCThreadState就是handle为0的ServiceManager进程访问Binder驱动的Binder线程。
那么综合这些代码,最后Binder.allowBlocking( )就是返回了一个ServiceManager进程访问Binder驱动的Binder线程,也就是封装成Framework层可以访问的BinderProxy。
(2)system_server进程通过BinderProxy.transact()将数据通过jni传递到BpBinder.transact()
这里体现了与应用层的跨进程Service的第二个不同点: 通过mRemote.transact()向Binder驱动发送数据的不同。
- 1)在应用层的跨进程Service:仅仅将interface token和方法参数写入到Parcel中
@Override public void setBaiduMessageTitle(java.lang.String msg) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeString(msg);
boolean _status = mRemote.transact(Stub.TRANSACTION_setBaiduMessageTitle, _data, _reply, 0);
.......
}
- 2)在ServiceManager:不仅将interface token和方法参数写入到Parcel中,而且把这次Stub写入到Parcel中
public void addService(String name, IBinder service, boolean allowIsolated)
throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IServiceManager.descriptor);
data.writeString(name);
data.writeStrongBinder(service);
data.writeInt(allowIsolated ? 1 : 0);
mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply, 0);
........
}
例如在SystemServer中通过下面的语句将WindowManagerService加入到ServiceManager中,
ServiceManager.addService(Context.WINDOW_SERVIEC,wm);
而这个wm就是一个IWindowManager.Stub的继承类。
这里简单补充一个transact()的最后一个参数代表的是与Binder驱动通信的一种机制:
- oneway机制:调用方非阻塞。Client不需要挂起线程等待。上面的两种都是采用的oneway机制。Binder驱动会串行化处理,排队一个个处理。如图
- 非oneway机制:调用方阻塞。
另外:
- 进程向Binder驱动发送指令都是以BC_开头;
- 有Binder驱动发给其他进程都是BR_开头
所以在应用层的跨进程服务和这个ServiceManager都是采用的oneway机制。
(3)BpBinder通过Binder线程IPCThreadState将数据发送给Binder驱动
通过IPCThreadState中通过ioctl,向Binder驱动发送BINDER_WRITE_READ指令。
status_t IPCThreadState::talkWithDriver(bool doReceive)
{
if (mProcess->mDriverFD <= 0) {
return -EBADF;
}
binder_write_read bwr;
const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
bwr.write_size = outAvail;
bwr.write_buffer = (uintptr_t)mOut.data();
.......
do {
.......
if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
.......
此时数据已经发送到Binder驱动。
(4)Binder驱动将数据发送给ServiceManager进程来处理消息
当Binder驱动接收到该信息之后,就会读取到system_server进程发送过来的数据,然后发送BR_TRANSACTION指令给到ServiceManager进程。在二 ServiceManager跨进程通信实现中也提到了,因为ServiceManager进程在启动的时候,就会维护着一个binde_loop()开启循环,时刻读取解析Binder驱动发送过来的消息,调用到service_manager.c中的do_add_service()。
详见Android 跨进程通信-(五)Binder机制之一次拷贝的原理中的二 ServiceManager进程接收到指令和三 ServiceManager进程binder_parse()解析BR_TRANSACTION指令以及
这里体现了与应用层的跨进程Service的第三个不同点: 服务进程处理方式不同。ServiceManager进程直接通过service_manager.c实现具体的接口方法实现,没有通过BBinder的transact()调用具体的Stub(ServiceManagerNative)的onTransact()来调用接口方法的实现。
(5)小结
system_server进程在通过ServiceManager.addService()的过程简单来说:
- 1)system_server进程获取与ServiceManager进程的Binder线程,转换成BinderProxy;
- 2)然后通过BinderProxy.transac()将信息通过jni传递到BpBinder.transact();
- 3)BpBinder通过Binder线程IPCThreadState通过ioctl向Binder驱动发送BINDER_WRITE_READ指令;
- 4)Binder驱动接收到指令之后,就会通知ServiceManager进程的循环来读取和解析Binder驱动发送的消息,调用service_manager.c中的do_add_service()完成服务注册。
三 ServiceManager之getService()( Framework层)
上一小结中,可以ServiceManager的addService()主要通过一系列的调用,最终有ServiceManager进程的service_manager.c来具体实现对Servcie的注册管理。而在ServiceManager.getService()的代码如下:
public static IBinder getService(String name) {
try {
IBinder service = sCache.get(name);
if (service != null) {
return service;
} else {
return Binder.allowBlocking(getIServiceManager().getService(name));
}
} catch (RemoteException e) {
Log.e(TAG, "error in getService", e);
}
return null;
}
这里会先从这个sCache的HashMap中取IBinder对象,但是在梳理addService()的时候,并没有将该Service添加到sCache,那么这个里面到底放的是哪些IBinder呢?
1.sCache初始化
从源码中可以看到,这里是直接将一个cache里面的内容添加到这个sCache中。
/**
* This is only intended to be called when the process is first being brought
* up and bound by the activity manager. There is only one thread in the process
* at that time, so no locking is done.
*
* @param cache the cache of service references
* @hide
*/
public static void initServiceCache(Map<String, IBinder> cache) {
if (sCache.size() != 0) {
throw new IllegalStateException("setServiceCache may only be called once");
}
sCache.putAll(cache);
}
从注释中也可以看到,这个方法调用的仅仅是在进程创建的时候由Activity Manager调用,是用来缓存Service的。
在前面的Android 跨进程通信-(十)Binder机制传输数据限制—罪魁祸首Binder线程池 的2.引入第二个疑问:一个APP启动的时候,存在多个Binder线程吗?中详细说明了:当一个APP/Service进程被Zygote进程fork出来之后,会加载ActivityThread类对应的功能,在ActivityThread#attach()的时候会调用到AMS的attachApplication(),最终会调用到ActivityThread#bindApplication()完成Application的实例化,代码如下:
public final void bindApplication(String processName, ApplicationInfo appInfo,
List<ProviderInfo> providers, ComponentName instrumentationName,
ProfilerInfo profilerInfo, Bundle instrumentationArgs,
IInstrumentationWatcher instrumentationWatcher,
IUiAutomationConnection instrumentationUiConnection, int debugMode,
boolean enableBinderTracking, boolean trackAllocation,
boolean isRestrictedBackupMode, boolean persistent, Configuration config,
CompatibilityInfo compatInfo, Map services, Bundle coreSettings,
String buildSerial) {
if (services != null) {
// Setup the service cache in the ServiceManager
ServiceManager.initServiceCache(services);
}
............
在这过程中会将AMS中通过getCommonServicesLocked(app.isolated);调用得到的这个集合的元素传入到该方法中,然后加到ServiceManager的缓存集合sCache中。
private HashMap<String, IBinder> getCommonServicesLocked(boolean isolated) {
// Isolated processes won't get this optimization, so that we don't
// violate the rules about which services they have access to.
if (isolated) {
if (mIsolatedAppBindArgs == null) {
mIsolatedAppBindArgs = new HashMap<>();
mIsolatedAppBindArgs.put("package", ServiceManager.getService("package"));
}
return mIsolatedAppBindArgs;
}
if (mAppBindArgs == null) {
mAppBindArgs = new HashMap<>();
// Setup the application init args
mAppBindArgs.put("package", ServiceManager.getService("package"));
mAppBindArgs.put("window", ServiceManager.getService("window"));
mAppBindArgs.put(Context.ALARM_SERVICE,
ServiceManager.getService(Context.ALARM_SERVICE));
}
return mAppBindArgs;
}
这个app.isolated对应着对android:isolatedProcess的设置。如果设置为true,则该Service就会在一个特殊的进程中,该进程与系统的其他进程分开且设有自己的权限,只能通过服务API才能通信。默认的为false。
所以默认的会将PackageManagerService、WindowManagerService以及AlarmService加入到这个ServiceManager的缓存集合sCache中。也就是当一个APP进程/Service进程启动的时候,都会将这三个服务的IBinder对象放到ServiceManager中进行缓存。当在APP进程/Service进程中获取这些服务的时候,会首先取得ServiceManager的缓存集合sCache中的元素。
遗留问题:但这样做的好处是什么呢?
2.Binder.allowBlocking(getIServiceManager().getService(name))
除去PackageManagerService、WindowManagerService以及AlarmService这三个,其他的系统服务都是通过BinderProxy.transact()调用到ServiceManager进程对应的方法来获取的系统服务器的IBinder对象。
四 ServiceManager在Native层管理系统服务
前面的都是在Framework层,system_server进程通过Framework层提供的API来调用实现对系统服务的注册和查询。当然对于一些系统Service ,如CameraService、MediaService等具体功能都是通过C++来实现具体的功能,那么ServiceManager也提供了在C++的实现方式,具体见/frameworks/native/libs/binder/IServiceManager.cpp。
在这里已经不需要通过BinderProxy,BpBinder;而是通过BpInterface来将数据传递到Binder驱动。这里暂时不过多去分析这个流程。
五 总结
简单的在整理这个过程中的一些点在总结下:
- 1.ServiceManage进程是有init进程创建出来的,会在Zygote进程之前加载;
- 2.ServiceManager进程功能加载的时候,会执行service_manager.c的main(),然后获取Binder驱动的设备文件"/dev/binder"的文件描述符、内存映射以及开启循环来接收Binder驱动发送过来的消息;
- 3.system_server进程与ServiceManager进程IPC,Client的具体实现类为ServiceManagerNative,其过程为:
- (1)system_server进程通过BinderInternal.getContextObject()获取ServiceManager进程的BpBinder,然后经过Binder.allowBlocking()转换成BinderProxy
- (2)system_server进程通过BinderProxy.tranact()将数据传递到BpBinder.tansact(),最后通过IPCThreadState将数据发送到Binder驱动;
- (3)Binder驱动接收到数据之后,就会通知ServiceManager进程的循环来接收解析这次的数据,完成这次的IPC
- 4.system_server进程的不同系统Service与ServiceManager进程的IPC的时候,都会建立一个Binder线程(IPCThreadState),用来向Binder驱动传递数据。
- 5.system_server进程与ServiceManager进程的IPC和应用层的AIDL服务的IPC有一些不同的地方:
- (1)BinderProxy的获取方式不同:system_server进程通过BinderInternal.getContextObject()获取ServiceManager进程的BpBinder,转换成BinderProxy,向Binder驱动传递数据;而应用层的服务是通过onBind()返回的BinderProxy;
- (2)mRemote.transact()传递的信息不同:system_server进程不仅将方法编号以及方法参数传递给Binder驱动,并且将该次Stub对象一起写入到Binder驱动;而应用层的服务只需将方法编号以及方法参数传递给Binder驱动
- (3)服务进程处理方式不同:Binder驱动将信息发送到Native的ServiceManager进程的具体实现的service_manager中。而应用层的服务需要通过Binder驱动将信息通过IPCThreadState传递给BBinder.transact(),调用到JavaBBinder.onTransact(),从而调用到Stub的具体实现类的onTransact()来完成具体功能的实现。
- 6.ServiceManager进程还提供了C++的实现方式,供那些通过C++实现功能的Client进程,如MediaService。
这次主要总结的是ServiceManager对系统Service的管理,后面再去总结下ActivityManangerService是怎么管理应用层的Service。
以上是关于Android 跨进程通信-Binder机制之ServiceManager对系统Service的管理的主要内容,如果未能解决你的问题,请参考以下文章