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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值