前文回顾:
Android8 binder源码学习分析笔记(三):
https://blog.csdn.net/g_i_a_o_giao/article/details/151365630?spm=1001.2014.3001.5502
Android8 binder源码学习分析笔记(二):
https://blog.csdn.net/g_i_a_o_giao/article/details/151221566?spm=1011.2415.3001.5331
Android8 binder源码学习分析笔记(一):
https://blog.csdn.net/g_i_a_o_giao/article/details/151365630?spm=1011.2415.3001.5331
在上一篇文章中,我们探讨了Binder驱动如何建立连接、创建线程池以及处理命令。现在,让我们把目光转向ServiceManager的启动过程,看看Binder在其中扮演的角色。
首先来看frameworks/native/cmds/servicemanager/servicemanager.rc中的配置。此处可以看到可执行文件位于/system/bin/servicemanager。(可以看到当servicemanager服务启动以后,会重启zygote service,证明servicemanager是在zygote之前启动的)。
service servicemanager /system/bin/servicemanagerclass core animationuser systemgroup system readproccriticalonrestart restart healthdonrestart restart zygoteonrestart restart audioserveronrestart restart mediaonrestart restart surfaceflingeronrestart restart inputflingeronrestart restart drmonrestart restart cameraserverwritepid /dev/cpuset/system-background/tasksshutdown critical
执行这个可执行文件,会调用frameworks/native/cmds/servicemanager/service_manager.c的main函数。那么我们来看看这个方法。可以看到主要是调用了binder_open方法来打开binder驱动,然后调用了binder_become_context_manager方法来使得serviceManager成为binder的服务管理器,最后就是调用binder_loop进入循环,处理客户端请求。
int main(int argc, char** argv)
{struct binder_state *bs; // Binder驱动状态结构体指针union selinux_callback cb; // SELinux回调函数联合体char *driver; // Binder驱动设备路径// 处理命令行参数:如果提供了参数,使用指定的Binder驱动设备// 否则默认使用"/dev/binder"if (argc > 1) {driver = argv[1];} else {driver = "/dev/binder";}// 打开Binder驱动并初始化Binder状态// 128*1024指定了Binder映射内存的大小(128KB)bs = binder_open(driver, 128*1024);if (!bs) {// 如果打开Binder驱动失败
#ifdef VENDORSERVICEMANAGER// 如果是供应商服务管理器,记录警告并进入无限休眠ALOGW("failed to open binder driver %s\n", driver);while (true) {sleep(UINT_MAX); // 永久休眠,避免频繁重启}
#else// 如果是系统服务管理器,记录错误并退出ALOGE("failed to open binder driver %s\n", driver);
#endifreturn -1;}// 将自己设置为Binder上下文管理器(服务管理器)// 这是Binder IPC机制中的核心角色,负责管理所有服务注册和查找if (binder_become_context_manager(bs)) {ALOGE("cannot become context manager (%s)\n", strerror(errno));return -1;}// 设置SELinux回调函数// 审计回调:用于SELinux访问决策的审计cb.func_audit = audit_callback;selinux_set_callback(SELINUX_CB_AUDIT, cb);// 日志回调:用于SELinux日志记录cb.func_log = selinux_log_callback;selinux_set_callback(SELINUX_CB_LOG, cb);// 根据编译类型获取相应的SELinux句柄
#ifdef VENDORSERVICEMANAGER// 供应商服务管理器使用供应商服务上下文句柄sehandle = selinux_android_vendor_service_context_handle();
#else// 系统服务管理器使用系统服务上下文句柄sehandle = selinux_android_service_context_handle();
#endifselinux_status_open(true); // 打开SELinux状态监视// 检查SELinux句柄是否有效if (sehandle == NULL) {ALOGE("SELinux: Failed to acquire sehandle. Aborting.\n");abort(); // 如果获取失败,终止进程}// 获取当前进程的安全上下文if (getcon(&service_manager_context) != 0) {ALOGE("SELinux: Failed to acquire service_manager context. Aborting.\n");abort(); // 如果获取失败,终止进程}// 进入Binder循环,处理来自客户端的请求// bs: Binder状态// svcmgr_handler: 处理服务管理器请求的回调函数binder_loop(bs, svcmgr_handler);return 0;
}
首先来看看binder_open函数。这个方法主要是调用open函数打开binder驱动,然后调用mmap方法映射共享内存(重要)。
/*** 打开Binder驱动并初始化Binder状态* * @param driver: Binder设备路径,如"/dev/binder"* @param mapsize: 要映射的共享内存大小* @return: 成功返回binder_state结构体指针,失败返回NULL*/
struct binder_state *binder_open(const char* driver, size_t mapsize)
{struct binder_state *bs;struct binder_version vers;// 分配binder_state结构体内存bs = malloc(sizeof(*bs));if (!bs) {errno = ENOMEM; // 设置错误号为内存不足return NULL;}// 1. 打开Binder设备文件// O_RDWR: 读写模式打开// O_CLOEXEC: 执行exec()时自动关闭文件描述符bs->fd = open(driver, O_RDWR | O_CLOEXEC);if (bs->fd < 0) {fprintf(stderr,"binder: cannot open %s (%s)\n",driver, strerror(errno));goto fail_open; // 跳转到错误处理}// 2. 检查Binder驱动版本是否兼容if ((ioctl(bs->fd, BINDER_VERSION, &vers) == -1) ||(vers.protocol_version != BINDER_CURRENT_PROTOCOL_VERSION)) {fprintf(stderr,"binder: kernel驱动版本 (%d) 与用户空间版本 (%d) 不同\n",vers.protocol_version, BINDER_CURRENT_PROTOCOL_VERSION);goto fail_open; // 版本不匹配,跳转到错误处理}// 3. 映射共享内存 - 这是Binder通信的核心bs->mapsize = mapsize;// mmap参数:// NULL: 由内核选择映射地址// mapsize: 映射区域大小// PROT_READ: 只读保护// MAP_PRIVATE: 私有映射,写时复制// bs->fd: 映射的文件描述符// 0: 偏移量为0bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);if (bs->mapped == MAP_FAILED) {fprintf(stderr,"binder: 无法映射设备 (%s)\n",strerror(errno));goto fail_map; // 映射失败,跳转到错误处理}return bs; // 成功返回初始化好的binder_state// 错误处理标签
fail_map:close(bs->fd); // 关闭文件描述符
fail_open:free(bs); // 释放分配的内存return NULL; // 返回NULL表示失败
}
再来看看binder_become_context_manager方法和binder_loop方法。在binder_become_context_manager方法中,根据之前创建的binder_state对象,将serviceManager设置为binder的服务管理器。在binder_loop方法中,创建一个循环来处理客户端的请求,与binder驱动进行通信。有点类似上篇文章提到的joinThreadPool方法。(详情可查看这篇笔记https://blog.csdn.net/g_i_a_o_giao/article/details/151365630?spm=1001.2014.3001.5502)
/*** 将当前进程设置为Binder上下文管理器* * @param bs: binder_state结构体指针* @return: ioctl调用结果,0表示成功,-1表示失败*/
int binder_become_context_manager(struct binder_state *bs)
{// 使用ioctl设置当前进程为Binder上下文管理器// BINDER_SET_CONTEXT_MGR: 特殊的ioctl命令// 0: 参数,在此命令中未使用return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
}/*** 进入Binder消息循环,处理传入的Binder请求* * @param bs: binder_state结构体指针* @param func: 处理Binder事务的回调函数*/
void binder_loop(struct binder_state *bs, binder_handler func)
{int res;struct binder_write_read bwr; // Binder读写结构uint32_t readbuf[32]; // 读取缓冲区// 初始化写操作参数(本次循环没有数据要写)bwr.write_size = 0;bwr.write_consumed = 0;bwr.write_buffer = 0;// 1. 通知Binder驱动本线程进入循环状态readbuf[0] = BC_ENTER_LOOPER; // 命令码:进入循环binder_write(bs, readbuf, sizeof(uint32_t));// 2. 主循环 - 持续处理Binder请求for (;;) {// 设置读操作参数bwr.read_size = sizeof(readbuf); // 读取缓冲区大小bwr.read_consumed = 0; // 已消耗数据初始为0bwr.read_buffer = (uintptr_t) readbuf; // 读取缓冲区地址// 3. 执行Binder读写操作(主要等待读取)// BINDER_WRITE_READ: 最常用的Binder ioctl命令res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);if (res < 0) {ALOGE("binder_loop: ioctl失败 (%s)\n", strerror(errno));break; // ioctl失败,退出循环}// 4. 解析并处理接收到的Binder数据res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);if (res == 0) {ALOGE("binder_loop: 收到意外回复?!\n");break; // 解析结果异常,退出循环}if (res < 0) {ALOGE("binder_loop: IO错误 %d %s\n", res, strerror(errno));break; // 解析错误,退出循环}}
}
我们继续分析一下这个binder_parse方法。这个方法主要负责解析从Binder驱动接收到的数据并处理相应的Binder命令。首先是读取命令码,然后根据命令码进行不同的处理。如果有回调的函数,则进行处理。
/*** 解析从Binder驱动接收到的数据并处理相应的Binder命令* * @param bs: binder状态结构体指针,包含Binder设备信息* @param bio: binder_io结构体指针,用于处理回复数据(可为NULL)* @param ptr: 要解析的数据缓冲区起始地址* @param size: 数据缓冲区的大小* @param func: 处理Binder事务的回调函数* @return: 1表示成功处理,0表示收到回复,-1表示错误*/
int binder_parse(struct binder_state *bs, struct binder_io *bio,uintptr_t ptr, size_t size, binder_handler func)
{int r = 1; // 默认返回值为1(继续处理)uintptr_t end = ptr + (uintptr_t) size; // 计算数据结束位置// 循环处理缓冲区中的所有命令while (ptr < end) {// 1. 读取命令码(32位无符号整数)uint32_t cmd = *(uint32_t *) ptr;ptr += sizeof(uint32_t); // 移动指针到下一个数据位置#if TRACE // 调试跟踪fprintf(stderr,"%s:\n", cmd_name(cmd));
#endif// 2. 根据命令码进行不同的处理switch(cmd) {case BR_NOOP: // 无操作命令break; // 直接跳过,不做任何处理case BR_TRANSACTION_COMPLETE: // 事务完成通知break; // 直接跳过,不做任何处理case BR_INCREFS: // 增加引用计数case BR_ACQUIRE: // 获取对象case BR_RELEASE: // 释放对象case BR_DECREFS: // 减少引用计数
#if TRACEfprintf(stderr," %p, %p\n", (void *)ptr, (void *)(ptr + sizeof(void *)));
#endif// 这些命令后跟一个binder_ptr_cookie结构,跳过这个结构ptr += sizeof(struct binder_ptr_cookie);break;case BR_TRANSACTION: { // 收到事务请求(最重要的命令)// 获取事务数据结构struct binder_transaction_data *txn = (struct binder_transaction_data *) ptr;// 检查数据长度是否足够if ((end - ptr) < sizeof(*txn)) {ALOGE("parse: txn too small!\n");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);// 根据事务标志处理回复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: { // 收到事务回复// 获取回复事务数据结构struct binder_transaction_data *txn = (struct binder_transaction_data *) ptr;// 检查数据长度是否足够if ((end - ptr) < sizeof(*txn)) {ALOGE("parse: reply too small!\n");return -1; // 数据不足,返回错误}binder_dump_txn(txn); // 调试输出回复信息(如果启用)// 如果有提供的bio结构,用回复数据初始化它if (bio) {bio_init_from_txn(bio, txn);bio = 0; // 置零防止后续重复处理} else {/* todo FREE BUFFER */ // 需要释放缓冲区(TODO注释)}ptr += sizeof(*txn); // 移动指针跳过回复数据结构r = 0; // 设置返回值为0(表示收到回复)break;}case BR_DEAD_BINDER: { // Binder对象死亡通知// 获取死亡通知结构struct binder_death *death = (struct binder_death *)(uintptr_t) *(binder_uintptr_t *)ptr;ptr += sizeof(binder_uintptr_t); // 移动指针// 调用注册的死亡回调函数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; // 返回处理结果
}
我们再回到service_manager中,可以看到调用binder_looper时,传递了binder_loop(bs, svcmgr_handler); svcmgr_handler函数。那么我们分析一下该函数。在这个函数中,首先进行了一系列异常处理,最核心的还是根据binder驱动返回的code进行相应的处理。如果传递过来的code是SVC_MGR_ADD_SERVICE,那么就会执行do_add_service方法。传递过来的是SVC_MGR_GET_SERVICE和SVC_MGR_CHECK_SERVICE,那么会执行do_find_service方法。
// 处理Binder事务的核心函数
// bs: Binder状态,包含Binder驱动相关的文件描述符和映射信息
// txn: 事务数据,包含本次事务的详细信息(如发送者PID/UID、事务代码等)
// msg: 输入消息,包含客户端发送的数据
// reply: 输出消息,用于向客户端返回处理结果
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; // 字符串指针(UTF-16)size_t len; // 字符串长度uint32_t handle; // Binder句柄uint32_t strict_policy; // 严格模式策略标志int allow_isolated; // 是否允许隔离进程访问// 检查事务目标是否为Service Manager本身// BINDER_SERVICE_MANAGER是Service Manager的固定句柄(0)if (txn->target.ptr != BINDER_SERVICE_MANAGER)return -1;// 处理PING事务(心跳检测)if (txn->code == PING_TRANSACTION)return 0; // 直接返回0表示成功// 从消息中读取严格模式策略(相当于Parcel::enforceInterface())strict_policy = bio_get_uint32(msg);// 读取接口描述符字符串(应为"android.os.IServiceManager")s = bio_get_string16(msg, &len);if (s == NULL) {return -1; // 读取失败返回错误}// 验证接口描述符是否正确// svcmgr_id是预定义的"android.os.IServiceManager"的UTF-16表示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相关处理:检查状态更新并重新加载策略句柄if (sehandle && selinux_status_updated() > 0) {
#ifdef VENDORSERVICEMANAGER// 供应商服务管理器使用不同的上下文句柄struct selabel_handle *tmp_sehandle = selinux_android_vendor_service_context_handle();
#else// 标准服务管理器使用普通服务上下文句柄struct selabel_handle *tmp_sehandle = selinux_android_service_context_handle();
#endifif (tmp_sehandle) {selabel_close(sehandle); // 关闭旧句柄sehandle = tmp_sehandle; // 更新为新句柄}}// 根据事务代码进行分发处理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; // 未找到服务,跳出switch// 将找到的服务句柄写入回复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;// 调用do_add_service执行实际添加操作if (do_add_service(bs, s, len, handle, txn->sender_euid,allow_isolated, txn->sender_pid))return -1; // 添加失败返回错误break;case SVC_MGR_LIST_SERVICES: {// 列出服务:首先读取请求的服务索引号uint32_t n = 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; // 权限不足返回错误}// 遍历服务链表找到第n个服务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;}// 默认回复:写入32位0值(表示操作成功但无额外数据)bio_put_uint32(reply, 0);return 0;
}
首先来看看do_add_service方法,在这个方法中,首先就是进行一系列异常处理,然后调用find_svc方法来判断是否已存在同名的服务,如果存在的话则先移除旧的死亡通知,再更新现有服务的句柄。如果不存在的话,则创建新的服务节点。并且注册服务死亡回调。
// 添加服务的具体实现函数
// bs: Binder状态,用于与Binder驱动交互
// s: 服务名称(UTF-16字符串)
// len: 服务名称长度
// handle: 要注册的Binder服务句柄
// uid: 调用者的用户ID
// allow_isolated: 是否允许隔离进程访问该服务
// spid: 调用者的进程ID
int do_add_service(struct binder_state *bs,const uint16_t *s, size_t len,uint32_t handle, uid_t uid, int allow_isolated,pid_t spid)
{struct svcinfo *si; // 服务信息结构体指针// 参数有效性检查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; // 权限不足返回错误}// 在现有服务列表中查找是否已存在同名服务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 {// 服务不存在,创建新的服务节点// 分配内存:基础结构大小 + 服务名称存储空间(包含终止符)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; // 设置Binder句柄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->next = svclist; // 将新节点插入链表头部svclist = si; // 更新链表头指针}// 增加Binder句柄的引用计数,防止服务被意外释放binder_acquire(bs, handle);// 注册死亡通知,当服务进程终止时能收到通知binder_link_to_death(bs, handle, &si->death);return 0; // 返回成功
}struct svcinfo *find_svc(const uint16_t *s16, size_t len)
{struct svcinfo *si;for (si = svclist; si; si = si->next) {if ((len == si->len) &&!memcmp(s16, si->name, len * sizeof(uint16_t))) {return si;}}return NULL;
}
我们继续去分析do_find_service方法,在这个方法中,同样是调用了find_svc方法在服务列表中查找指定名称的服务,如果找到了,就进行一系列的检查,通过检查以后返回对应服务的句柄。
// 查找服务的具体实现函数
// s: 要查找的服务名称(UTF-16字符串)
// len: 服务名称长度
// uid: 调用者的用户ID
// spid: 调用者的进程ID
// 返回值: 找到的服务句柄,如果未找到或没有权限访问则返回0
uint32_t do_find_service(const uint16_t *s, size_t len, uid_t uid, pid_t spid)
{// 在服务列表中查找指定名称的服务struct svcinfo *si = find_svc(s, len);// 检查服务是否存在且具有有效句柄if (!si || !si->handle) {return 0; // 服务不存在或句柄无效,返回0}// 检查隔离进程访问权限if (!si->allow_isolated) {// 如果此服务不允许从隔离进程访问,// 则检查UID是否为隔离进程// 计算应用ID(去除用户ID部分)uid_t appid = uid % AID_USER;// 检查应用ID是否在隔离进程范围内if (appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END) {return 0; // 调用者是隔离进程且服务不允许访问,返回0}}// 权限检查:确认调用者有权查找此服务if (!svc_can_find(s, len, spid, uid)) {return 0; // 权限不足,返回0}// 所有检查通过,返回找到的服务句柄return si->handle;
}
再回到最初的binder_loop中,执行完func以后,会根据事务的标志判断需不需要返回。不需要的话就会释放掉缓冲区,需要的话就会调用binder_send_reply方法,将事务的处理结果返回。
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);}// 发送Binder回复的函数
// bs: Binder状态,用于与Binder驱动通信
// reply: 包含回复数据的binder_io结构
// buffer_to_free: 需要释放的缓冲区指针(之前分配的事务缓冲区)
// status: 事务处理状态,非0表示错误状态
void binder_send_reply(struct binder_state *bs,struct binder_io *reply,binder_uintptr_t buffer_to_free,int status)
{// 定义一个打包的数据结构,包含两个Binder命令和事务数据// 使用packed属性确保编译器不会在结构成员之间添加填充字节struct {uint32_t cmd_free; // 释放缓冲区的命令binder_uintptr_t buffer; // 要释放的缓冲区指针uint32_t cmd_reply; // 发送回复的命令struct binder_transaction_data txn; // 事务数据} __attribute__((packed)) data;// 设置释放缓冲区命令data.cmd_free = BC_FREE_BUFFER; // Binder命令:释放缓冲区data.buffer = buffer_to_free; // 要释放的缓冲区地址// 设置回复命令data.cmd_reply = BC_REPLY; // Binder命令:发送回复// 初始化事务数据结构data.txn.target.ptr = 0; // 目标对象指针(回复不需要特定目标)data.txn.cookie = 0; // 附加数据(通常用于Binder对象)data.txn.code = 0; // 事务代码(回复通常为0)// 根据状态码设置不同的回复内容if (status) {// 错误状态:只返回状态码data.txn.flags = TF_STATUS_CODE; // 设置状态码标志data.txn.data_size = sizeof(int); // 数据大小为int的大小data.txn.offsets_size = 0; // 没有Binder对象偏移量data.txn.data.ptr.buffer = (uintptr_t)&status; // 数据指向状态码data.txn.data.ptr.offsets = 0; // 没有偏移量数组} else {// 正常状态:返回完整的回复数据data.txn.flags = 0; // 清除所有标志data.txn.data_size = reply->data - reply->data0; // 计算数据大小data.txn.offsets_size = ((char*) reply->offs) - ((char*) reply->offs0); // 计算偏移量大小data.txn.data.ptr.buffer = (uintptr_t)reply->data0; // 数据缓冲区起始地址data.txn.data.ptr.offsets = (uintptr_t)reply->offs0; // 偏移量数组起始地址}// 将组合好的数据写入Binder驱动binder_write(bs, &data, sizeof(data));
}
通过源码分析,整个ServiceManager的流程就已经很清晰了:
-
Service Manager启动后调用
binder_loop()
进入等待状态 -
当客户端想要添加/查找服务时,向Binder驱动发送事务
-
Binder驱动将事务传递给Service Manager进程
-
binder_loop()
收到消息,调用svcmgr_handler()
处理 -
Service Manager处理完成后,调用
binder_send_reply()
发送回复 -
Binder驱动将回复传递回客户端进程