对于ServiceManager的使用,我们在应用程序编程时也会经常使用到,比如我们需要使用Sensor时,我们一般会做如下的调用:
mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE); mSensorManager.registerListener(this, mAccelerometer,SensorManager.SENSOR_DELAY_UI); @Override public void onSensorChanged(SensorEvent event) { if(event.sensor.getType() != Sensor.TYPE_ACCELEROMETER) return; ... }
这样的编程模式,API说明会告诉我们,每次系统里加速度计Sensor发生状态变化时,就会触发onSensorChanged()回调方法被执行来处理Sensor的变动信息。这里就很好地说明了在系统范围内使用Service的另一种模式,就是通过getSystemService(),取回一个System Service的引用实例,然后便可以调用Service实现的方法,比如我们例子里的mSensorManager.registerListener()方法。
我们可以继承跟踪代码的实现,getSystemService()也并没有什么神奇的,它本质上只是创建一个Service列表的Cache而已,把ContextImpl.java与getSystemService()相关的实现抽出来,于是我们可以得到:
class ContextImpl extends Context { ... static class ServiceFetcher { 4 int mContextCacheIndex = -1; public Object getService(ContextImpl ctx) { 5 ArrayList<Object> cache = ctx.mServiceCache; Object service; synchronized (cache) { if (cache.size() == 0) { for (int i =0; i <sNextPerContextServiceCacheIndex; i++) { cache.add(null); } } else { service =cache.get(mContextCacheIndex); if (service != null) { return service; } } service = createService(ctx); cache.set(mContextCacheIndex,service); return service; } } public Object createService(ContextImpl ctx) { 6 throw new RuntimeException("Notimplemented"); } } private static final HashMap<String, ServiceFetcher> SYSTEM_SERVICE_MAP = new HashMap<String,ServiceFetcher>(); 2 private static int sNextPerContextServiceCacheIndex = 0; private static void registerService(String serviceName, ServiceFetcher fetcher) { 3 if(!(fetcher instanceof StaticServiceFetcher)) { fetcher.mContextCacheIndex = sNextPerContextServiceCacheIndex++; } SYSTEM_SERVICE_MAP.put(serviceName, fetcher); } static { registerService(ACCESSIBILITY_SERVICE, new ServiceFetcher() { 7 public Object getService(ContextImpl ctx) { returnAccessibilityManager.getInstance(ctx); }}); registerService(ACTIVITY_SERVICE, new ServiceFetcher() { 8 public Object createService(ContextImpl ctx) { return newActivityManager(ctx.getOuterContext(), ctx.mMainThread.getHandler()); }}); registerService(ALARM_SERVICE, new StaticServiceFetcher() { 9 public Object createStaticService() { IBinder b = ServiceManager.getService(ALARM_SERVICE); IAlarmManager service =IAlarmManager.Stub.asInterface(b); return new AlarmManager(service); }}); ... } @Override public Object getSystemService(String name) { 1 ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name); return fetcher == null ? null : fetcher.getService(this); } ... }}
在这个整体的执行流程里,比较绕,而且深入代码分析时,我们也会看到在实现时的不一致,风格并非很严谨。但通过中间插入的这层ServiceFetcher,可以让应用程序(或是某种需要使用getSystemService()方法的系统组件)很快找到合适的ServiceProxy端的初始化方法,快速建立起跟RemoteService的通信。
除了getSystemService()方法与bindService()不同以外,在这时我们看不到两者的任何区别。当然,我们在bindService()里也会使用到onServiceConnected()回调方法异步地返回一个IBinder引用,但这也只是出于Service的生命周期考虑的结果。bindService()只是通过Intent找到合适的Service,而具体远程Service的Binder引用,则是通过onServiceConnected()。所以本质上getSystemService()与bindService()只是形式上的区别,本质上是一回事,成功调用之后便可以进行一样的RPC操作请求了。
我们可以注意到getService()与bindService()的一个重要区别,bindService()与unbindService()成对,而getService()只是单独出现。于是,bindService()这种调用机制上的Service,总是在Bounded生命周期里才能对外提供服务,可以做到按需启动,不再需要时便会在合适的时间点被关闭。而getService()所操作的Service则没有什么生命周期,永远在系统里运行并提供服务,这里也需要有种实体可以管理这些Service,当这些Service无人使用时,承载该Service的进程便会进入休眠中,这便是ServiceManager的Stub端所完成的功能。
ServiceManager在Java和Native环境里各有其实现,但在Java端实际上只有Proxy端,而Native环境里实现的servicemanager才具有完整的Proxy与Stub实现。
我们可以先来看ServiceManager.java的实现:
public finalclass ServiceManager { private staticfinal String TAG = "ServiceManager"; private static IServiceManagersServiceManager; private static IServiceManagergetIServiceManager() { if(sServiceManager != null) { return sServiceManager; } sServiceManager =ServiceManagerNative.asInterface(BinderInternal.getContextObject()); 2 return sServiceManager; } public static IBindergetService(String name) { try { IBinder service = sCache.get(name); if (service != null) { return service; } else { returngetIServiceManager().getService(name); 1 } } catch (RemoteException e) { Log.e(TAG, "error in getService", e); } return null; }
代码如此简洁,于是我们可以跟踪ServiceManagerNative的实现。从ServiceManagerNative类的实现上,我们也可以看到基于Binder收发两端的实现,但实际上接收端没有意义,也不会被执行到。代码如下:
package android.os; import java.util.ArrayList; public abstractclass ServiceManagerNative extends Binder implements IServiceManager 1 { static public IServiceManagerasInterface(IBinder obj) { if(obj == null) { return null; } IServiceManager in = (IServiceManager)obj.queryLocalInterface(descriptor); if(in != null) { return in; } return new ServiceManagerProxy(obj); 2 } publicServiceManagerNative() { attachInterface(this, descriptor); } public boolean onTransact(int code, Parcel data,Parcel reply,int flags) { ... } public IBinderasBinder() { return this; } } class ServiceManagerProxy implements IServiceManager { publicServiceManagerProxy(IBinder remote) { mRemote = remote; } public IBinderasBinder() { return mRemote; } public IBindergetService(String name) throws RemoteException { 3 Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IServiceManager.descriptor); data.writeString(name); mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0); IBinder binder = reply.readStrongBinder(); reply.recycle(); data.recycle(); return binder; } public IBindercheckService(String name)throws RemoteException { … return binder; } public void addService(Stringname, IBinder service,boolean allowIsolated) throws RemoteException { … } public String[]listServices() throws RemoteException { ArrayList<String> services = new ArrayList<String>(); int n = 0; while (true) { … } return array; } public voidsetPermissionController(IPermissionController controller) throws RemoteException { … } private IBindermRemote; }
此时,如果系统里有某种实现,在标签同是“android.os.IServiceManager”的Binder通信管道上监听,并响应getService()等方法的调用请求,这时整个基于ServiceManager的模型便完美了。我们可以继续使用ActivityManagerService实现时同样的技巧,继承ServiceManagerNative并且实现一个onTransact()所需要的响应方法,但这样的方式性能不够好,不利于频繁调用。
Java语言环境本身只是一种虚拟机环境,Java虚拟机在实现上强调的是对底层的封装,并不会提供针对操作系统的某种功能,如果我们想实现对底层的访问,则必须使用JNI来访问。比如访问Binder,如果把这样的机制通过指令或是IO拓展的方式直接嵌入到Java语言里,则会引发Android系统与Java语言的更大分裂。于是Binder本身是通过JNI拓展到Java语言里的,这样同时还达到一个高效的目的,虽然Java语言里可以访问到Binder的相应操作接口,但在底层实际上是通过C++实现的更高效的版本。既然Binder已经是C++实现,再通过JNI引入到Java环境里,我们的ServiceManager的Stub实现就没有必要到Java环境里再重复一次了,可以直接在底层将IServiceManager接口所需要的远程方法实现即可。这种方式更符合Java语法习惯、Native实现可以得到更高效ServiceManager,另外还提供了进一步实现NativeSerivce的可能性。既然底层是C++实现的,于是可以将Service的逻辑用C++写出来,再通过Binder直接暴露到应用程序层即可。
作为IServerManager的Stub端,它所需要完成的功能是提供getService()、addService()等方法,并通过这些远程方法来控制什么状态下进程应该处于活跃状态,而什么时间点促使进进入休眠。到目前为此,它只需要给Java环境里的ServiceManager类提供服务,但稍后面我们就会看到,它也需要提供同样的服务接口给Native环境里的用C++语言编写的ServiceManager类。出于这样需求,于是干脆这一代码就用C语言来实现,以区别于使用服务的Java环境和C++环境里的对象。
ServiceManager会是一个在init.rc里定义的一个系统进程,在系统运行时全局有效。在Android系统里,唯一会与底层Binder驱动直接交互的,便是servicemanager进程(系统里其他部分,都是通过libbinder封装之后使用统一的访问模型来进行)。监听在Binder驱动 之上的servicemanager进程,相当于Android世界里的“大内总管”。一方面,系统内存在的Service,并非全局都知道,只有通过servicemanager才能查询到;另一方面,所谓的System Service也需要有一种类似于RemoteService的收发自如的执行能力,被调用时便投入运行,而没有被调用到时,虽不能被杀死掉,但也不会盲目的“空转”执行。出于这样的需求,便有servicemanager的实现框架。
无论出于什么样的设计需求,servicemanager都需要承当起service的管理功能,从一般的设计上来考察,或许这一实现会很复杂,但事实上并非如此。整个servicemanager的实现非常精练,加上binder通信的处理过程,总共不超过一千行代码,而且是使用C语言写出来的精练代码。Servicemanager的源代码位于frameworks/base/cmds/servicemanager里,通过service_manager.c实现主控部分,通过binder.c来实现与binder的通信处理过程。
既然是C语言代码,我们可以先从main()方法分析起。
int main(int argc,char **argv) { struct binder_state*bs; void *svcmgr =BINDER_SERVICE_MANAGER; bs= binder_open(128*1024); 1 if(binder_become_context_manager(bs)) { 2 ALOGE("cannot becomecontext manager (%s)\n", strerror(errno)); return -1; } svcmgr_handle = svcmgr; binder_loop(bs, svcmgr_handler); 3 return 0; }
从这一个main()函数实现,我们可以看出servicemanager在实现上的简洁性。本质上,只进行了三步操作:
这种简洁的实现,就使servicemanager这个进程有能力解析binder命令,然后根据不同命令调度不同进程进入执行时的活跃状态,或是在不再被用到时进入到休眠状态。我们把上述三个步骤打开,就可以看到这一执行过程:
打开驱动并映射128K字节空间。在后面对binder驱动的分析我们可以看到,这是android系统里唯一一次使用这样的方式来访问binder,通过这样的方式,则servicemanager可以直接操作binder驱动来分配的一段内存,而其他进程会通过ioctl的系统调用将操作请求,从用户态拷贝到servicemanager的这段内核空间的内存。通过这种方式,减少了一次内存拷贝(servicemanager直接映射使用内核空间的binder区域)。
struct binder_state *binder_open(unsigned mapsize) { struct binder_state*bs; bs= malloc(sizeof(*bs)); if (!bs) { errno = ENOMEM; return 0; } bs->fd = open("/dev/binder", O_RDWR); if (bs->fd < 0) { fprintf(stderr,"binder:cannot open device (%s)\n", strerror(errno)); goto fail_open; } bs->mapsize = mapsize; bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd,0); if (bs->mapped ==MAP_FAILED) { fprintf(stderr,"binder:cannot map device (%s)\n", strerror(errno)); goto fail_map; } /* TODO: check version */ return bs; fail_map: close(bs->fd); fail_open: free(bs); return 0; }
这就只是通过ioctl来操作一次binder驱动而已。
int binder_become_context_manager(struct binder_state *bs) { returnioctl(bs->fd, BINDER_SET_CONTEXT_MGR,0); }
这一实现复杂一点,就是循环地从binder取回binder消息,然后再通过传入的回调函数循环处理binder消息。
void binder_loop(struct binder_state *bs, binder_handler func) { int res; structbinder_write_read bwr; 1 unsigned readbuf[32]; bwr.write_size = 0; bwr.write_consumed = 0; bwr.write_buffer = 0; readbuf[0] = BC_ENTER_LOOPER; 2 binder_write(bs, readbuf, sizeof(unsigned)); for (;;) { bwr.read_size = sizeof(readbuf); 3 bwr.read_consumed = 0; bwr.read_buffer = (unsigned) readbuf; res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr); if(res < 0) { ALOGE("binder_loop:ioctl failed (%s)\n", strerror(errno)); break; } res = binder_parse(bs, 0, readbuf, bwr.read_consumed, func); 4 if(res == 0){ ALOGE("binder_loop:unexpected reply?!\n"); break; } if(res < 0) { ALOGE("binder_loop:io error %d %s\n", res, strerror(errno)); break; } } }
由于binder_loop()函数实现复杂一些,于是我们更细一点的来进行分析。从实现原理来看,它所需要做的就是循环从binder驱动读回IPC信息,然后再进行处理。于是,综合得到的具体步骤是:
再看binder_parse()函数,我们可以看到Binder会循环地读取read_buf,根据不同命令作不同处理。在这个方法里,我们看到全是BR_开头的命令,在后面分析Binder运行原理时可以看到,BC是Binder Command的缩写,BC_开头的命令会全都是发出操作,而BR则是Bind Return的缩写,BR_开头的命令只会用于操作结果的返回,也就是说servicemanager进行的是被动地响应。而只有两种情况会引发后续的处理:BR_TRANSACTION,会触发Binder消息的后续处理;而BR_DEAD_BINDER,则会触发Binder相关资源的回收。
int binder_parse(struct binder_state *bs,struct binder_io *bio, uint32_t *ptr, uint32_t size,binder_handler func) { int r = 1; uint32_t *end = ptr + (size / 4); while (ptr < end) { uint32_t cmd = *ptr++; switch(cmd) { case BR_NOOP: break; case BR_TRANSACTION_COMPLETE: break; case BR_INCREFS: case BR_ACQUIRE: case BR_RELEASE: case BR_DECREFS: ptr += 2; break; case BR_TRANSACTION: { struct binder_txn *txn = (void *) ptr; if((end - ptr) * sizeof(uint32_t) < sizeof(struct binder_txn)) { return -1; } binder_dump_txn(txn); if(func) { unsigned rdata[256/4]; struct binder_io msg; struct binder_io reply; int res; bio_init(&reply, rdata, sizeof(rdata),4); bio_init_from_txn(&msg,txn); res = func(bs, txn, &msg,&reply); binder_send_reply(bs,&reply, txn->data, res); } ptr += sizeof(*txn) / sizeof(uint32_t); break; } case BR_REPLY: { struct binder_txn *txn = (void*) ptr; if((end - ptr) * sizeof(uint32_t) < sizeof(struct binder_txn)) { return -1; } binder_dump_txn(txn); if(bio) { bio_init_from_txn(bio, txn); bio = 0; } ptr += (sizeof(*txn) / sizeof(uint32_t)); r = 0; break; } case BR_DEAD_BINDER: { struct binder_death *death = (void*) *ptr++; death->func(bs, death->ptr); break; } case BR_FAILED_REPLY: r = -1; break; case BR_DEAD_REPLY: r = -1; break; default: ALOGE("parse: OOPS%d\n", cmd); return -1; } } return r; }
如果在binder_parse()函数里得到的Binder消息会是BR_TRANSACTION,我们从后面对Binder驱动的描述可以看出,此时则会是通过proxy对象发过来的命令请求。我们从名字也大概可以看出一些端倪,BR_TRANSACTION,不是Binder发送时的transact发送,这必然会是onTransact(),用来处理Binder命令的接收处理。
由于Binder在传输时会使用很严整的结构以标识其IPC传输过程,于是,在servicemanager实现里,使用了两个新的结构体用于binder消息的规整化,binder_txn与binder_io,binder_txn是binder消息的包头,跟内核态使用的binder_transaction_data结构一致,而binder_io则会进一步将binder传输时使用的buffer有效段位进一步准确地描述出来。
struct binder_txn { void *target; 1 void *cookie; 2 uint32_t code; 3 uint32_t flags; 4 uint32_t sender_pid; 5 uint32_t sender_euid; 6 uint32_t data_size; 7 uint32_t offs_size; 8 void *data; 9 void *offs; 10 };
Binder传输的是如此严整的数据结构,则在进行处理时提供了多种可能的处理功能,所以从servicemanager层面来看来,也不只是简单地将数据读出来,而会是通过不同的结构来进行消息体的解析。虽然我们在后面的binder机制分析时还将看到binder_tranaction_data结构,我们这里也看一下其含义:
有了这样数据结构,我们对BR_TRANSACTION的处理就比较容易理解了,在servicemanager里,我们会有数据的收发处理,但对底层来说,都是binder_txn结构的数据格式,而对于上层处理,都是通过binder_io结构来完成。所以,在这时会将收到的buffer,通过bio_init_from_txn()转换成binder_io,同时准备好应答的缓冲区,通过bio_init()来规整这一缓冲区。然后这两个binder_io指向的消息体会通过回调函数func()进行处理,处理完则通过binder_send_reply()将func回调函数处理得到的应答消息写回Binder,从而通知到调用servicemanager的地方。
回过头去看binder_loop()函数,会发现其实处理binder的回调函数func,是由service_manager.c里的svcmgr_handler()函数来实现的。这样实际在底层代码也完成了抽离,binder.c实现的是Binder通用处理,而servicemanager.c实现的则是专门的ServiceManager的处理逻辑。对于svcmgr_handler(),则跟Java环境里的onTransact()区别不大了:
int svcmgr_handler(struct binder_state *bs, struct binder_txn*txn, struct binder_io *msg, struct binder_io *reply) 1 { struct svcinfo *si; uint16_t *s; unsigned len; void *ptr; uint32_t strict_policy; int allow_isolated; if (txn->target !=svcmgr_handle) 2 return -1; strict_policy = bio_get_uint32(msg); 3 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) { 4 caseSVC_MGR_GET_SERVICE: caseSVC_MGR_CHECK_SERVICE: 5 s = bio_get_string16(msg, &len); ptr = do_find_service(bs, s, len, txn->sender_euid); if(!ptr) break; bio_put_ref(reply, ptr); return 0; caseSVC_MGR_ADD_SERVICE: 6 s = bio_get_string16(msg, &len); ptr = bio_get_ref(msg); allow_isolated = bio_get_uint32(msg) ? 1 :0; if(do_add_service(bs, s, len, ptr, txn->sender_euid, allow_isolated)) return -1; break; caseSVC_MGR_LIST_SERVICES: { 7 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: ALOGE("unknown code %d\n",txn->code); return -1; } bio_put_uint32(reply, 0); return 0; }
通过引入servicemanager这样一种机制,在我们系统设计上就得到方便,我们不再需要系统内部的bindService(),但又提供了类似于bindService()这样按需启动的功能。我们在系统里实现的一个Remote Service,也就是SystemService,在它启动时会调用add_service()函数将自己加入到servicemanager的svcinfo链表里,然后进入休眠。虽然大部分情况下,我们都是使用Java来实现System Service,但由于在实现上是Java端发送Binder命令,Native端实现的servicemanager进程来接收并处理Binder命令,于是本质上是一回事。serviamanger维护了svcinfo链表之后,实际上service在没有被用到时,都是在休眠状态。客户端则可以通过get_service()来发送Binder消息到servicemanager,此时servicemanager会告诉客户端该service是否存在,并且在存在的情况下,返回service的IBinder引用到客户端,并同时唤醒service,于是后续的流程上,客户端就可以直接通过IBinder引用(也就是通过asInterface()方法得到的Proxy对象),直接跟service进行RPC交互了。如图所示:
在某个Service对象完成自己的初始化后,就会调用add_service(),将自己加入到Service列表,然后就会在Binder驱动上休眠。应用程序会调用get_service(),尝试跟某个SystemService建立交互,此时也在Binder驱动上休眠。当servicemanager做完合法性判断之后,则会唤醒收发两端的进程进入到交互过程里。从这个意义上来说,servicemanager虽然代码如此简单,但也起到了“大内总管”的职能,会管理System Service,并在合适点唤醒它们投入执行。
既然一个简单的Service Manager,调用频度不那么高,也会直接通过C这样的Native语言来编写,get_service()/add_service()的调用频度比Binder通信要低多了,那我们Binder通信本身也应该使用native实现了。另外,Java语言本身并不知道Binder的存在,为了支持Binder这种特殊的IPC,我们也应该使用Native编码来导入Binder IPC通信,问题在于Native的程度会有多深。出于频率上的考虑,Binder通信大部分都使用Native实现,只是给Java环境提供一层封装,供Java环境直接使用,这就是libbinder,由frameworks/base/libs/binder来实现。从Android 4.1开始,为了使NDK与Native实现兼容,这一目录已经换至frameworks/native/libs/binder,与NDK环境共享。