Android 跨进程通信-(十一)Binder机制之ServiceManager对系统Service的管理

目录

前言

一 ServiceManager进程

二 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进程来处理消息

(5)小结

三 ServiceManager之getService()( Framework层)

1.sCache初始化

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。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值