IPC浅析Binder进程通信和ServiceManager

Posted 從前以後

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了IPC浅析Binder进程通信和ServiceManager相关的知识,希望对你有一定的参考价值。

Binder机制是android中实现的进程间通信的架构,它采用的是C-S架构,Client通过代理完成对Server的调用。既然是C-S模式,那么谁是Server呢?答案就是Native中的进程:ServiceManager。
顾名思义,这个是用来管理所有Server的。Android设备在硬件启动之后,第一个进程就是init进程,init进程启动之后,会启动另外一系列的进程,其中最重要的就是Zygote进程和ServiceManager进程,身下的如VM和Runtime等等进程,ServiceManager进程启动之后其他Server就可以通过ServiceManager的add_service和check_service来添加和获取特定的server了。

关于ServiceMananger:
ServiceMananger是android中比较重要的一个进程,它是在init进程启动之后启动。ServiceMananger是系统服务的管理者,包括Java层的系统服务,比如:WindowManagerService、ActivityManagerService等,以及Native层的系统服务,例如SurfaceFlingerdeng 。在ServiceManager中有两个比较重要的方法:add_service、check_service。系统的service需要通过add_service把自己的信息注册到ServiceManager中,当需要使用时,通过check_service检查该service是否存在,并通过find_service返回。

既然Service Manager组件是用来管理Server并且向Client提供查询Server远程接口的,Service Manger、Client和Server三者分别是运行在独立的进程当中,这样它们之间的通信也属于进程间通信了,而且也是采用Binder机制进行进程间通信,因此,Service Manager在充当Binder机制的守护进程的角色的同时,也在充当Server的角色,然而,它是一种特殊的Server,下面就来领略下它的特殊之处。

int main(int argc, char **argv)  
  
    struct binder_state *bs;  
    void *svcmgr = BINDER_SERVICE_MANAGER;  

    bs = binder_open(128*1024);  

    if (binder_become_context_manager(bs))   
        LOGE("cannot become context manager (%s)\\n", strerror(errno));  
        return -1;  
      

    svcmgr_handle = svcmgr;  
    binder_loop(bs, svcmgr_handler);  
    return 0;  

从main函数中看出,init大值做了一下事情:
1,打开BinderDriver设备。
2,通知BinderDriver设备,把自己变成context_manager。
3开启循环,不停的去读BinderDriver设备,看是否有对service的请求,如果有的话,就去调用svcmgr_handler函数回调处理请求。

int svcmgr_handler(struct binder_state *bs, 
struct binder_txn *txn, 
struct binder_io *msg, 
struct binder_io *reply) 
 
struct svcinfo *si; 
uint16_t *s; 
unsigned len; 
void *ptr; 
uint32_t strict_policy; 
// LOGI("target=%p code=%d pid=%d uid=%d\\n", 
// txn->target, txn->code, txn->sender_pid, txn->sender_euid); 
if (txn->target != svcmgr_handle) 
return -1; 
// Equivalent to Parcel::enforceInterface(), reading the RPC 
// header with the strict mode policy mask and the interface name. 
// Note that we ignore the strict_policy and don't propagate it 
// further (since we do no outbound RPCs anyway). 
strict_policy = bio_get_uint32(msg); 
s = bio_get_string16(msg, &len); 
if ((len != (sizeof(svcmgr_id) / 2)) || 
memcmp(svcmgr_id, s, sizeof(svcmgr_id)))  
fprintf(stderr,"invalid id %s\\n", str8(s)); 
return -1; 
 
switch(txn->code)  
case SVC_MGR_GET_SERVICE: 
case SVC_MGR_CHECK_SERVICE: 
s = bio_get_string16(msg, &len); 
ptr = do_find_service(bs, s, len); 
if (!ptr) 
break; 
bio_put_ref(reply, ptr); 
return 0; 
case SVC_MGR_ADD_SERVICE: 
s = bio_get_string16(msg, &len); 
ptr = bio_get_ref(msg); 
if (do_add_service(bs, s, len, ptr, txn->sender_euid)) 
return -1; 
breakcase SVC_MGR_LIST_SERVICES:  
unsigned n = bio_get_uint32(msg); 
si = svclist; 
while ((n-- > 0) && si) 
si = si->next; 
if (si)  
bio_put_string16(reply, si->name); 
return 0; 
 
return -1; 
 
default: 
LOGE("unknown code %d\\n", txn->code); 
return -1; 
 
bio_put_uint32(reply, 0); 
return 0; 
 

在该回调函数中会判断Service有什么需要,如果是请求注册service,那么久执行:case SVC_MGR_ADD_SERVICE,该方法通过ServiceManager,把服务加入到BinderDriver中。如果是获取service,那么执行上文case SVC_MGR_CHECK_SERVICE: 并把返回的数据写入reply,返回给客户端。
服务端注册完Service到BinderDriver中,客户端请求绑定拿到IBinder接口对象,那么就可以愉快的通信了。

Binder进行进程间通信
上文只是提到了怎么注册服务和获取到注册服务返回值。究竟是怎么拿到返回值的,并且Binder究竟是怎么传输数据的呢?
下面以startActivity为例子,探究怎么找到AMS,并且传输数据的。
首先Activity是继承自Context的,Context的实现类是ContextImpl,那么就会调用ContextImpl里面的startActivity方法

  @Override
    public void startActivity(Intent intent, Bundle options) 
        warnIfCallingFromSystemProcess();
        if ((intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) 
            throw new AndroidRuntimeException(
                    "Calling startActivity() from outside of an Activity "
                    + " context requires the FLAG_ACTIVITY_NEW_TASK flag."
                    + " Is this really what you want?");
        
        mMainThread.getInstrumentation().execStartActivity(
            getOuterContext(), mMainThread.getApplicationThread(), null,
            (Activity)null, intent, -1, options);

接着会调用到Instrumentation中的execStartActivity方法

public ActivityResult execStartActivity(
            Context who, IBinder contextThread, IBinder token, Activity target,
            Intent intent, int requestCode, Bundle options) 
        IApplicationThread whoThread = (IApplicationThread) contextThread;
        if (mActivityMonitors != null) 
            synchronized (mSync) 
                final int N = mActivityMonitors.size();
                for (int i=0; i<N; i++) 
                    final ActivityMonitor am = mActivityMonitors.get(i);
                    if (am.match(who, null, intent)) 
                        am.mHits++;
                        if (am.isBlocking()) 
                            return requestCode >= 0 ? am.getResult() : null;
                        
                        break;
                    
                
            
        
        try 
            intent.migrateExtraStreamToClipData();
            intent.prepareToLeaveProcess();
            int result = ActivityManagerNative.getDefault()
                .startActivity(whoThread, who.getBasePackageName(), intent,
                        intent.resolveTypeIfNeeded(who.getContentResolver()),
                        token, target != null ? target.mEmbeddedID : null,
                        requestCode, 0, null, null, options);
            checkStartActivityResult(result, intent);
         catch (RemoteException e) 
        
        return null;

Instrumentation中的execStartActivity方法中ActivityManagerNative.getDefault()该方法通过ServiceManager的get方法拿到远程的IBinder实现类对象(为什么是IBinder类型?ActivityManagerNative继承自Binder),同时调用该接口实现类对象的startActivity方法
最终调用到ActivityManagerProxy中的startActivity

 public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,
            String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, String profileFile,
            ParcelFileDescriptor profileFd, Bundle options) throws RemoteException 
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IActivityManager.descriptor);
        data.writeStrongBinder(caller != null ? caller.asBinder() : null);
        data.writeString(callingPackage);
        intent.writeToParcel(data, 0);
        data.writeString(resolvedType);
        data.writeStrongBinder(resultTo);
        data.writeString(resultWho);
        data.writeInt(requestCode);
        data.writeInt(startFlags);
        data.writeString(profileFile);
        if (profileFd != null) 
            data.writeInt(1);
            profileFd.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
         else 
            data.writeInt(0);
        
        if (options != null) 
            data.writeInt(1);
            options.writeToParcel(data, 0);
         else 
            data.writeInt(0);
        
        mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
        reply.readException();
        int result = reply.readInt();
        reply.recycle();
        data.recycle();
        return result;
    

最终调用IBinder接口方法transact写入数据到BinderDriver中,Service从BinderDriver读取数据,执行完之后在原路返回数据给客户端。
Binder到底是个啥?在Java层Binder是一个实现了IBinder类,在Linux中Binder是一个驱动。本人认为Binder实际是Linux中的一块驱动而已,实现数据交换,至于Java层和Native层的Binder,实际上是实现了IBinder接口,利用IBinder中的transact写入数据到Binder驱动中。所以Java层和Native层的Binder本人认为是伪Binder,只是提供方法写入数据到BinderDriver中而已。

以上是关于IPC浅析Binder进程通信和ServiceManager的主要内容,如果未能解决你的问题,请参考以下文章

IPC初识进程和Binder

Android进程间通信(IPC)机制Binder简要介绍和学习计划

Android系统进程间通信(IPC)机制Binder中的Server启动过程源代码分析

转Android进程间通信(IPC)机制Binder简要介绍和学习计划

Android Binder设计与实现篇

Android IPC机制—Binder的工作机制