Binder机制研究

在安卓系统中,每一个应用程序都是由一些ActivityService组成的,这些ActivityService有可能运行在同一个进程中,也有可能运行在不同的进程中。而不在同一个进程中的ActivityService就要通过binder进行通讯。课程ppt中有对binder机制的简要介绍,这里我又做了一些个人的研究。

 

Binder

Android系统的Binder机制中,由一系统组件组成,分别是ClientServerService ManagerBinder驱动程序,其中ClientServerService Manager运行在用户空间,Binder驱动程序运行内核空间。Binder就是一种把这四个组件粘合在一起的粘结剂了,其中,核心组件便是Binder驱动程序了,Service Manager提供了辅助管理的功能,ClientServer正是在Binder驱动和Service Manager提供的基础设施上,进行Client-Server之间的通信。

总结一下,Android系统Binder机制中的四个组件ClientServerService ManagerBinder驱动程序的关系如下图所示:


1. ClientServerServiceManager实现在用户空间中,Binder驱动程序实现在内核空间中

2. Binder驱动程序和ServiceManagerAndroid平台中已经实现,开发者只需要在用户空间实现自己的ClientServer

 3. Binder驱动程序提供设备文件/dev/binder与用户空间交互,ClientServerServiceManager通过openioctl文件操作函数与Binder驱动程序进行通信

 4. ClientServer之间的进程间通信通过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需要将一个binderserver发送时,可以调用此函数。

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实例。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值