IPC(三)浅析Binder进程通信和ServiceManager

来源:互联网 发布:淘宝走势在哪看 编辑:程序博客网 时间:2024/05/11 17:58

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 0
原创粉丝点击