在安卓系统中,每一个应用程序都是由一些Activity和Service组成的,这些Activity和Service有可能运行在同一个进程中,也有可能运行在不同的进程中。而不在同一个进程中的Activity和Service就要通过binder进行通讯。课程ppt中有对binder机制的简要介绍,这里我又做了一些个人的研究。
Binder
在Android系统的Binder机制中,由一系统组件组成,分别是Client、Server、Service Manager和Binder驱动程序,其中Client、Server和Service Manager运行在用户空间,Binder驱动程序运行内核空间。Binder就是一种把这四个组件粘合在一起的粘结剂了,其中,核心组件便是Binder驱动程序了,Service Manager提供了辅助管理的功能,Client和Server正是在Binder驱动和Service Manager提供的基础设施上,进行Client-Server之间的通信。
总结一下,Android系统Binder机制中的四个组件Client、Server、Service Manager和Binder驱动程序的关系如下图所示:
1. Client、Server和ServiceManager实现在用户空间中,Binder驱动程序实现在内核空间中
2. Binder驱动程序和ServiceManager在Android平台中已经实现,开发者只需要在用户空间实现自己的Client和Server
3. Binder驱动程序提供设备文件/dev/binder与用户空间交互,Client、Server和ServiceManager通过open和ioctl文件操作函数与Binder驱动程序进行通信
4. Client和Server之间的进程间通信通过Binder驱动程序间接实现
5. Service Manager是一个守护进程,用来管理Server,并向Client提供查询Server接口的能力
本地Binder框架
包含以下类(frameworks/native/libs/binder):
RefBase, IInterface,BnInterface,BpInterface,BpRefBase,Parcel 等等
service manager
ServiceMananger是安卓中比较重要的一个进程,它是在init进程启动之后启动,用来管理系统中的service。比如:InputMethodService、ActivityManagerService等。在ServiceManager中有两个比较重要的方法:add_service、check_service。系统的service需要通过add_service把自己的信息注册到ServiceManager中,当需要使用时,通过check_service检查该service是否存在。任何service在被使用之前,均要向Service Manager注册,同时客户端需要访问某个service时,应该首先向Service Manager查询是否存在该服务。如果Service Manage存在这个service,那么会将该service的handle返回给client,handle是每个service的唯一标识符。
在Service Manager的主函数中,首先打开/dev/binder设备,并在内存中映射128K的空间,然后通知Binder设备,把自己变成context_manager,最后进入循环,不停的去读Binder设备,看是否有对service的请求,如果有的话,就去调用svcmgr_handler函数回调处理请求。
1. int main(int argc, char **argv)
2. {
3. struct binder_state *bs;
4. void *svcmgr = BINDER_SERVICE_MANAGER;
5. bs = binder_open(128*1024);
6. if (binder_become_context_manager(bs)) {
7. LOGE("cannot become context manager (%s)\n", strerror(errno));
8. return -1;
9. }
10. svcmgr_handle = svcmgr;
11. binder_loop(bs, svcmgr_handler);
12. return 0;
13. }
在ServiceManger中注册服务,用的回调函数svcmgr_handler,在该回调函数中会判断Service有什么需要,如果是请求注册service,那么就执行SVC_MGR_ADD_SERVICE
1. int svcmgr_handler(struct binder_state *bs,
2. struct binder_txn *txn,
3. struct binder_io *msg,
4. struct binder_io *reply)
5. {
6. struct svcinfo *si;
7. uint16_t *s;
8. unsigned len;
9. void *ptr;
10. uint32_t strict_policy;
11. // LOGI("target=%p code=%d pid=%d uid=%d\n",
12. // txn->target, txn->code, txn->sender_pid, txn->sender_euid);
13. if (txn->target != svcmgr_handle)
14. return -1;
15. // Equivalent to Parcel::enforceInterface(), reading the RPC
16. // header with the strict mode policy mask and the interface name.
17. // Note that we ignore the strict_policy and don't propagate it
18. // further (since we do no outbound RPCs anyway).
19. strict_policy = bio_get_uint32(msg);
20. s = bio_get_string16(msg, &len);
21. if ((len != (sizeof(svcmgr_id) / 2)) ||
22. memcmp(svcmgr_id, s, sizeof(svcmgr_id))) {
23. fprintf(stderr,"invalid id %s\n", str8(s));
24. return -1;
25. }
26. switch(txn->code) {
27. case SVC_MGR_GET_SERVICE:
28. case SVC_MGR_CHECK_SERVICE:
29. s = bio_get_string16(msg, &len);
30. ptr = do_find_service(bs, s, len);
31. if (!ptr)
32. break;
33. bio_put_ref(reply, ptr);
34. return 0;
35. case SVC_MGR_ADD_SERVICE:
36. s = bio_get_string16(msg, &len);
37. ptr = bio_get_ref(msg);
38. if (do_add_service(bs, s, len, ptr, txn->sender_euid))
39. return -1;
40. break;
41. case SVC_MGR_LIST_SERVICES: {
42. unsigned n = bio_get_uint32(msg);
43. si = svclist;
44. while ((n-- > 0) && si)
45. si = si->next;
46. if (si) {
47. bio_put_string16(reply, si->name);
48. return 0;
49. }
50. return -1;
51. }
52. default:
53. LOGE("unknown code %d\n", txn->code);
54. return -1;
55. }
56. bio_put_uint32(reply, 0);
57. return 0;
58. }
ProcessState
ProcessState是以单例模式设计的。每个进程在使用binder机制通信时,均需要维护一个ProcessState实例来描述当前进程在binder通信时的binder状态。ProcessState有如下2个主要功能:1.创建一个thread,该线程负责与内核中的binder模块进行通信,称该线程为Pool thread; 2.为指定的handle创建一个BpBinder对象,并管理该进程中所有的BpBinder对象。
Parcel
Parcel是binder IPC中的最基本的通信单元,它存储C-S间函数调用的参数.但是Parcel只能存储基本的数据类型,如果是复杂的数据类型的话,在存储时,需要将其拆分为基本的数据类型来存储。
1. writeStrongBinder
当client需要将一个binder向server发送时,可以调用此函数。
virtual status_t addService(const String16& name, const sp<IBinder>& service)
{
Parcel data, reply;
data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
data.writeString16(name);
data.writeStrongBinder(service);
status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
return err == NO_ERROR ? reply.readExceptionCode() : err;
}
2.readStrongBinder
当server端收到client的调用请求之后,如果需要返回一个binder时,可以向BD发送这个binder,当IPCThreadState实例收到这个返回的Parcel时,client可以通过这个函数将这个被server返回的binder读出。
sp<IBinder> Parcel::readStrongBinder() const
{
sp<IBinder> val;
unflatten_binder(ProcessState::self(), *this, &val);
return val;
}
主要基类
基类IInterface
为server端提供接口,它的子类声明了service能够实现的所有的方法;
基类IBinder
BBinder与BpBinder均为IBinder的子类,因此可以看出IBinder定义了binder IPC的通信协议,BBinder与BpBinder在这个协议框架内进行的收和发操作,构建了基本的binder IPC机制。
基类BpRefBase
client端在查询SM获得所需的的BpBinder后,BpRefBase负责管理当前获得的BpBinder实例。