servicemanager之事件处理

servicemanager之启动过程中,有看到servicemanager在一切准备工作就绪后,就进入binder_loop()开始不停的处理事件,这篇笔记重点分析下这些核心事件时如何处理的。

命令解析: binder_parse()

首先要解析命令,根据不同的命令进行不同的动作。从下面的代码看,servicemanager支持的命令并不太多,这里只关注BR_TRANSACTION。

int binder_parse(struct binder_state *bs, struct binder_io *bio, uintptr_t ptr, size_t size, binder_handler func)
{
    int r = 1;
    uintptr_t end = ptr + (uintptr_t) size;

    while (ptr < end) {
		// 命令(4字节)
        uint32_t cmd = *(uint32_t *) ptr;
        ptr += sizeof(uint32_t);

        switch(cmd) {
        case BR_NOOP:
        case BR_TRANSACTION_COMPLETE:
        case BR_INCREFS:
        case BR_ACQUIRE:
        case BR_RELEASE:
        case BR_DECREFS:
        case BR_TRANSACTION:
			// 来自client的IPC调用,调用信息都在binder_transaction_data中
            struct binder_transaction_data *txn = (struct binder_transaction_data *) ptr;
            if ((end - ptr) < sizeof(*txn)) {
                ALOGE("parse: txn too small!\n");
                return -1;
            }
            if (func) {
                unsigned rdata[256/4];
                struct binder_io msg;
                struct binder_io reply;
                int res;
				// 初始化reply(将reply.data指向rdata),后面可能需要向调用者发送响应
                bio_init(&reply, rdata, sizeof(rdata), 4);
				// 根据txn初始化msg,后面用msg来解析驱动传递的数据
                bio_init_from_txn(&msg, txn);
				// func就是svcmgr_handler(),处理IPC调用
                res = func(bs, txn, &msg, &reply);
				// 对于oneway类型的IPC调用,不需要发送响应
                if (txn->flags & TF_ONE_WAY) {
                    binder_free_buffer(bs, txn->data.ptr.buffer);
                } else {
                    binder_send_reply(bs, &reply, txn->data.ptr.buffer, res);
                }
            }
			// 继续处理下一个
            ptr += sizeof(*txn);
            break;
        case BR_REPLY:
        case BR_DEAD_BINDER:
        case BR_FAILED_REPLY:
        case BR_DEAD_REPLY:
        default:
        }
    }
    return r;
}

初始化消息解析

void bio_init_from_txn(struct binder_io *bio, struct binder_transaction_data *txn)
{
    bio->data = bio->data0 = (char *)(intptr_t)txn->data.ptr.buffer;
    bio->offs = bio->offs0 = (binder_size_t *)(intptr_t)txn->data.ptr.offsets;
    bio->data_avail = txn->data_size;
    bio->offs_avail = txn->offsets_size / sizeof(size_t);
    bio->flags = BIO_F_SHARED;
}

事务类型的命令携带的消息的首部是struct binder_transaction_data,该首部指明了是什么事务:

struct binder_transaction_data {
  // target表示应该由谁来处理该IPC调用,特别的,当target.handle=0的时候,表示应该由servicemanager来处理
  union {
    __u32 handle;
    binder_uintptr_t ptr;
  } target;
  binder_uintptr_t cookie;
  // 操作码,代表要做什么
  __u32 code;
  __u32 flags;
  // 调用方的身份信息
  pid_t sender_pid;
  uid_t sender_euid;
  // 根据操作码解释的数据部分
  binder_size_t data_size;
  binder_size_t offsets_size;
  // 指向事务携带的数据区,使用下面的struct binder_io来操作该数据区
  union {
    struct {
      binder_uintptr_t buffer;
      binder_uintptr_t offsets;
    } ptr;
    __u8 buf[8];
  } data;
};

此外,为了方便缓冲区参数的解析的填充,servicemanager还定义了struct binder_io。

struct binder_io
{
	// 在处理过程中,data会逐渐移动,但是data0永远指向消息的开头
    char *data;            /* pointer to read/write from */
    binder_size_t *offs;   /* array of offsets */
    size_t data_avail;     /* bytes available in data buffer */
    size_t offs_avail;     /* entries available in offsets array */

    char *data0;           /* start of data buffer */
    binder_size_t *offs0;  /* start of offsets buffer */
    uint32_t flags;
    uint32_t unused;
};

事务命令处理: BR_TRANSACTION

int svcmgr_handler(struct binder_state *bs, struct binder_transaction_data *txn,
	struct binder_io *msg, struct binder_io *reply)
{
    struct svcinfo *si;
    uint16_t *s;
    size_t len;
    uint32_t handle;
    uint32_t strict_policy;
    int allow_isolated;
    uint32_t dumpsys_priority;

	// 判断下是否就是发送给自己的消息(ptr为0,即handle为0)
    if (txn->target.ptr != BINDER_SERVICE_MANAGER)
        return -1;
	// PING操作用于保活,直接返回成功
    if (txn->code == PING_TRANSACTION)
        return 0;

    // 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);
    // 解析servicemanager的名字,格式:字符串中字符个数(4字节)+字符串(每个字符2字节)
    s = bio_get_string16(msg, &len);
    if (s == NULL) {
        return -1;
    }
	// 校验binder接口名字,调用者必须指定为"android.os.IServiceManger"
    if ((len != (sizeof(svcmgr_id) / 2)) || memcmp(svcmgr_id, s, sizeof(svcmgr_id))) {
        fprintf(stderr,"invalid id %s\n", str8(s, len));
        return -1;
    }
	// SELinux相关,忽略
...
	// 根据操作码确定client需要servicemanager做什么,可以看出,
	// 实际上servicemanager能干的核心事务只有查询和添加Service
    switch(txn->code) {
    case SVC_MGR_GET_SERVICE:
    case SVC_MGR_CHECK_SERVICE: // 获取服务
		// 获取要查找的服务的名称
        s = bio_get_string16(msg, &len);
        if (s == NULL) {
            return -1;
        }
		// 查找服务
        handle = do_find_service(s, len, txn->sender_euid, txn->sender_pid);
        if (!handle)
            break;
		// 将找到的服务句柄记录到reply中返回
        bio_put_ref(reply, handle);
        return 0;
    case SVC_MGR_ADD_SERVICE:// 添加服务,即注册服务
		// 获取要添加的服务的名字
        s = bio_get_string16(msg, &len);
        if (s == NULL) {
            return -1;
        }
		// 获取服务句柄(binder驱动已经分配好了,这里只是读取)
        handle = bio_get_ref(msg);
        allow_isolated = bio_get_uint32(msg) ? 1 : 0;
        dumpsys_priority = bio_get_uint32(msg);
		// 添加服务
        if (do_add_service(bs, s, len, handle, txn->sender_euid, allow_isolated, dumpsys_priority, txn->sender_pid))
            return -1;
        break;
    case SVC_MGR_LIST_SERVICES: { // 列举所有已注册服务
        uint32_t n = bio_get_uint32(msg);
        uint32_t req_dumpsys_priority = bio_get_uint32(msg);
		// 检查调用者身份
        if (!svc_can_list(txn->sender_pid, txn->sender_euid)) {
            ALOGE("list_service() uid=%d - PERMISSION DENIED\n", txn->sender_euid);
            return -1;
        }
        si = svclist;
        // walk through the list of services n times skipping services that
        // do not support the requested priority
        while (si) {
            if (si->dumpsys_priority & req_dumpsys_priority) {
                if (n == 0) break;
                n--;
            }
            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有调用do_add_service()进行服务的添加操作,至于为服务分配句柄,实际上是binder驱动做的,servicemanager这里仅仅是从驱动传递过来的数据中获取该句柄而已。

int do_add_service(struct binder_state *bs, const uint16_t *s, size_t len, uint32_t handle,
	uid_t uid, int allow_isolated, uint32_t dumpsys_priority, pid_t spid)
{
    struct svcinfo *si;

	// 服务句柄不能为0,并且服务名字必须提供,并且长度不能超过127个字符
    if (!handle || (len == 0) || (len > 127))
        return -1;
	// 检查调用者是否有权限注册服务
    if (!svc_can_register(s, len, spid, uid)) {
        ALOGE("add_service('%s',%x) uid=%d - PERMISSION DENIED\n", str8(s, len), handle, uid);
        return -1;
    }
	// 以服务名字为key检查是否已经有相同名字的服务
    si = find_svc(s, len);
    if (si) {
		// 对于重复注册的服务,会更新其服务句柄
        if (si->handle) {
            ALOGE("add_service('%s',%x) uid=%d - ALREADY REGISTERED, OVERRIDE\n", str8(s, len), handle, uid);
            svcinfo_death(bs, si);
        }
        si->handle = handle;
    } else {
		// 分配svcinfo对象用于保存注册的服务信息(包括末尾的服务名字)
        si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t));
        if (!si) {
            ALOGE("add_service('%s',%x) uid=%d - OUT OF MEMORY\n", str8(s, len), handle, uid);
            return -1;
        }
        si->handle = handle;
        si->len = len;
        memcpy(si->name, s, (len + 1) * sizeof(uint16_t));
        si->name[len] = '\0';
        si->death.func = (void*) svcinfo_death;
        si->death.ptr = si;
        si->allow_isolated = allow_isolated;
        si->dumpsys_priority = dumpsys_priority;
		// 插入到服务列表的首部
        si->next = svclist;
        svclist = si;
    }
	// 通过binder驱动增加对该服务的引用计数
    binder_acquire(bs, handle);
    binder_link_to_death(bs, handle, &si->death);
    return 0;
}

如上,servicemanager对每个注册的服务对应一个struct svcinfo结构,其中保存了servicemanager需要保存的信息,并且servicemanager将所有已注册的服务组织到全局的单链表svclist中。

// 每个注册的服务在servicemanger中抽象成一个svcinfo对象
struct svcinfo
{
    struct svcinfo *next;
	// 服务句柄,每个服务提供者都应该提供一个该句柄,并且该句柄在服务提供者进程中是唯一的
    uint32_t handle;
	// 服务销毁信息
    struct binder_death death;
    int allow_isolated;
	// 每个服务可以指定一个dumpsys优先级,用于控制dumpsys是否可以dump到该服务
    uint32_t dumpsys_priority;
	// 服务名字信息
    size_t len;
    uint16_t name[0];
};

剩下的查找服务和列举服务实现不再赘述。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值