温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Android系统中Binder子系统有什么用

发布时间:2021-11-23 14:20:07 来源:亿速云 阅读:167 作者:小新 栏目:系统运维

这篇文章主要介绍了Android系统中Binder子系统有什么用,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。

        binder 系统的核心是另种通信方式:IPC 和 RPC。IPC 是 src A 直接发给 des B,而 RPC 是 src A 通过远程函数调用 des B。

        1、IPC 通信的方式有三个要素:

            1. 发送源:A;

            2. 目的:B 向 servicemanger 注册 led 服务,A 向 servicemanger 查询 led 服务,得到一个 handle;

            3. 数据本身:char buf[512];

        2、RPC 通信方式是远程函数调用:

            1. 调用的是哪个函数:sever 的函数编号;

            2. 传给它什么参数,返回值。通过 IPC 的 buf 传输。

        example:LED 传输。IPC 方式是从 A 直接发送给B;而 RPC 方式是 led_open、led_ctl 进行封装数据,然后发送给 B,在 B 那边调用 led_open,led_ctl 再次取出数据。

        我们先来大概介绍下 client、servicemanger、server 三个的作用。

        client:

            1. 打开驱动;

            2. 获取服务:向 servicemanger 查询服务,获得一个 handle;

            3. 向 handle 发送数据。

        servicemanger:

            1. 打开驱动;

            2. 告诉驱动,它是 “servicemanger”;

            3. while(1) {

                    读驱动获取数据;

                    解析数据;

                    调用:a. 注册服务:在链表中记录服务名;

                              b. 获取服务:b.1 在链表中查询有无此服务;b.2 返回 “server进程”的 handle。

             };

        server:

            1. 打开驱动;

            2. 注册服务:向 servicemanger 发送服务;

            3. while(1) {

                    读驱动获取数据;

                    解析数据;

                    调用对应函数。

             };

    它们三个都是基于 binder 驱动进行工作。我们先来看看 service_manger.c 文件,mian 函数大体如下

int main(int argc, char **argv) {     struct binder_state *bs;     bs = binder_open(128*1024);      // 对应上面的第一步。打开驱动     if (!bs) {         ALOGE("failed to open binder driver\n");         return -1;     }     if (binder_become_context_manager(bs)) {         ALOGE("cannot become context manager (%s)\n", strerror(errno));         return -1;     }     selinux_enabled = is_selinux_enabled();     sehandle = selinux_android_service_context_handle();     if (selinux_enabled > 0) {         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();         }     }     union selinux_callback cb;     cb.func_audit = audit_callback;     selinux_set_callback(SELINUX_CB_AUDIT, cb);     cb.func_log = selinux_log_callback;     selinux_set_callback(SELINUX_CB_LOG, cb);     svcmgr_handle = BINDER_SERVICE_MANAGER;     // 对应上面的第二步。告诉驱动,它是 ServiceManager     binder_loop(bs, svcmgr_handler);                  // 对应上面的第三步。 while 循环所做的事情     return 0; }

    我们再来看看 binder.c (对应于上面的 server),其中 binder_loop 函数就在此文件中。我们来看看 binder_loop 函数所做的事情,code 如下

void binder_loop(struct binder_state *bs, binder_handler func) {     int res;     struct binder_write_read bwr;     uint32_t readbuf[32];     bwr.write_size = 0;     bwr.write_consumed = 0;     bwr.write_buffer = 0;     readbuf[0] = BC_ENTER_LOOPER;     binder_write(bs, readbuf, sizeof(uint32_t));     for (;;) {         bwr.read_size = sizeof(readbuf);         bwr.read_consumed = 0;         bwr.read_buffer = (uintptr_t) 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, (uintptr_t) readbuf, bwr.read_consumed, func); // 解析数据         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;         }     } }

    我们再来看看 bctest.c 文件(对应于上面的 client),code 如下

int main(int argc, char **argv) {     int fd;     struct binder_state *bs;     uint32_t svcmgr = BINDER_SERVICE_MANAGER;     uint32_t handle;     bs = binder_open(128*1024);     if (!bs) {         fprintf(stderr, "failed to open binder driver\n");         return -1;     }     argc--;     argv++;     while (argc > 0) {         if (!strcmp(argv[0],"alt")) {             handle = svcmgr_lookup(bs, svcmgr, "alt_svc_mgr");             if (!handle) {                 fprintf(stderr,"cannot find alt_svc_mgr\n");                 return -1;             }             svcmgr = handle;             fprintf(stderr,"svcmgr is via %x\n", handle);         } else if (!strcmp(argv[0],"lookup")) {             if (argc < 2) {                 fprintf(stderr,"argument required\n");                 return -1;             }             handle = svcmgr_lookup(bs, svcmgr, argv[1]);          // 获取服务             fprintf(stderr,"lookup(%s) = %x\n", argv[1], handle);             argc--;             argv++;         } else if (!strcmp(argv[0],"publish")) {             if (argc < 2) {                 fprintf(stderr,"argument required\n");                 return -1;             }             svcmgr_publish(bs, svcmgr, argv[1], &token);          // 注册服务             argc--;             argv++;         } else {             fprintf(stderr,"unknown command %s\n", argv[0]);             return -1;         }         argc--;         argv++;     }     return 0; }

    先来看看 svcmgr_lookup 函数是怎么来获取服务的,code 如下

uint32_t svcmgr_lookup(struct binder_state *bs, uint32_t target, const char *name) {     uint32_t handle;     unsigned iodata[512/4];     struct binder_io msg, reply;     // 构造 binder_io     bio_init(&msg, iodata, sizeof(iodata), 4);     bio_put_uint32(&msg, 0);  // strict mode header     bio_put_string16_x(&msg, SVC_MGR_NAME);     bio_put_string16_x(&msg, name);     if (binder_call(bs, &msg, &reply, target, SVC_MGR_CHECK_SERVICE))    // 获取服务         return 0;     handle = bio_get_ref(&reply);     if (handle)         binder_acquire(bs, handle);     binder_done(bs, &msg, &reply);     return handle; }

    我们看到其中核心函数是 binder_call 函数。再来看看 svcmgr_publish 函数是怎么来注册服务的,code 如下

int svcmgr_publish(struct binder_state *bs, uint32_t target, const char *name, void *ptr) {     int status;     unsigned iodata[512/4];     struct binder_io msg, reply;     bio_init(&msg, iodata, sizeof(iodata), 4);     bio_put_uint32(&msg, 0);  // strict mode header     bio_put_string16_x(&msg, SVC_MGR_NAME);     bio_put_string16_x(&msg, name);     bio_put_obj(&msg, ptr);     if (binder_call(bs, &msg, &reply, target, SVC_MGR_ADD_SERVICE))    // 注册服务         return -1;     status = bio_get_uint32(&reply);     binder_done(bs, &msg, &reply);     return status; }

    其中核心函数还是 binder_call 函数。binder_call 函数的参数作用分别是:1、远程调用;2、向谁发送数据;3、调用那个函数;4、提供什么参数;5、返回值。

    那么 binder_call 函数中的参数作用如下:

        1、bs 是一个结构体, 代表远程调用;

        2、msg 中含有服务的名字;

        3、reply 中含有servicemanager回复的数据, 表示提供服务的进程;

        4、target 代表是的 0,表示servicemanager, (if (target == 0));

        5、SVC_MGR_CHECK_SERVICE 表示要调用servicemanager中的"getservice函数"。

    下来我们具体来看看 binder_call 的实现

int binder_call(struct binder_state *bs,                 struct binder_io *msg, struct binder_io *reply,                 uint32_t target, uint32_t code) {     int res;     struct binder_write_read bwr;     struct {         uint32_t cmd;         struct binder_transaction_data txn;     } __attribute__((packed)) writebuf;     unsigned readbuf[32];     if (msg->flags & BIO_F_OVERFLOW) {         fprintf(stderr,"binder: txn buffer overflow\n");         goto fail;     }     // 构造参数     writebuf.cmd = BC_TRANSACTION;     writebuf.txn.target.handle = target;     writebuf.txn.code = code;     writebuf.txn.flags = 0;     writebuf.txn.data_size = msg->data - msg->data0;     writebuf.txn.offsets_size = ((char*) msg->offs) - ((char*) msg->offs0);     writebuf.txn.data.ptr.buffer = (uintptr_t)msg->data0;     writebuf.txn.data.ptr.offsets = (uintptr_t)msg->offs0;     bwr.write_size = sizeof(writebuf);     bwr.write_consumed = 0;     bwr.write_buffer = (uintptr_t) &writebuf;     hexdump(msg->data0, msg->data - msg->data0);     for (;;) {         bwr.read_size = sizeof(readbuf);         bwr.read_consumed = 0;         bwr.read_buffer = (uintptr_t) readbuf;         res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);    // 调用 ioctl 发数据         if (res < 0) {             fprintf(stderr,"binder: ioctl failed (%s)\n", strerror(errno));             goto fail;         }         res = binder_parse(bs, reply, (uintptr_t) readbuf, bwr.read_consumed, 0);         if (res == 0) return 0;         if (res < 0) goto fail;     } fail:     memset(reply, 0, sizeof(*reply));     reply->flags |= BIO_F_IOERROR;     return -1; }

    我们看到在 writebuf 中构造参数,构造参数放在 buf 中,用 binder_io 来描述。先把 binder_io 转换为 binder_write_read;在 ioctl 中调用它来发送数据;最后在 binder_parse 函数将 binder_write_read 转换为 binder_io。

    下来我们再来看看 IPC 是怎么进行数据交互的。我们前面说了,IPC 传输方式有三个要素:

        1. 源(自己)

        2. 目的:用 handle 表示“服务”,即向实现该“服务”的进程发送数据;handle 是“服务”的引用。

        3. 数据。

    handle 是进程 A 对进程 B 提供的服务 S 的引用。

    下来我们来解释下上面那句话中的一些关键词:

        引用,code 如下

struct binder_ref {     /* Lookups needed: */     /*   node + proc => ref (transaction) */     /*   desc + proc => ref (transaction, inc/dec ref) */     /*   node => refs + procs (proc exit) */     int debug_id;     struct rb_node rb_node_desc;     struct rb_node rb_node_node;     struct hlist_node node_entry;     struct binder_proc *proc;     struct binder_node *node;     uint32_t desc;     int strong;     int weak;     struct binder_ref_death *death; };

        我们看到 binder_ref 结构体中有个 binder_node 结构体,这个 binder_node 便指的是服务 S。code 如下

struct binder_node {     int debug_id;     struct binder_work work;     union {         struct rb_node rb_node;         struct hlist_node dead_node;     };     struct binder_proc *proc;     struct hlist_head refs;     int internal_strong_refs;     int local_weak_refs;     int local_strong_refs;     void __user *ptr;     void __user *cookie;     unsigned has_strong_ref:1;     unsigned pending_strong_ref:1;     unsigned has_weak_ref:1;     unsigned pending_weak_ref:1;     unsigned has_async_transaction:1;     unsigned accept_fds:1;     unsigned min_priority:8;     struct list_head async_todo; };

        在 binder_node 结构体中有个 binder_proc 结构体,这个 binder_proc 便指的是进程 B。code 如下

struct binder_proc {     struct hlist_node proc_node;     struct rb_root threads;     struct rb_root nodes;     struct rb_root refs_by_desc;     struct rb_root refs_by_node;     int pid;     struct vm_area_struct *vma;     struct mm_struct *vma_vm_mm;     struct task_struct *tsk;     struct files_struct *files;     struct hlist_node deferred_work_node;     int deferred_work;     void *buffer;     ptrdiff_t user_buffer_offset;     struct list_head buffers;     struct rb_root free_buffers;     struct rb_root allocated_buffers;     size_t free_async_space;     struct page **pages;     size_t buffer_size;     uint32_t buffer_free;     struct list_head todo;     wait_queue_head_t wait;     struct binder_stats stats;     struct list_head delivered_death;     int max_threads;     int requested_threads;     int requested_threads_started;     int ready_threads;     long default_priority;     struct dentry *debugfs_entry; };

        在 binder_proc 结构体中有个 threads 结构体,这个 threads 便指的是多线程。code 如下

struct binder_thread {     struct binder_proc *proc;     struct rb_node rb_node;     int pid;     int looper;     struct binder_transaction *transaction_stack;     struct list_head todo;     uint32_t return_error; /* Write failed, return error code in read buf */     uint32_t return_error2; /* Write failed, return error code in read */         /* buffer. Used when sending a reply to a dead process that */         /* we are also waiting on */     wait_queue_head_t wait;     struct binder_stats stats; };

    现在我们就知道多线程是怎么来进行信息的传输了。

    server 传入一个 flat_binder_object 给驱动:

        1. 在内核态驱动里为每个服务创建 binder_node。binder_node.proc = server 进程

        2. service_manger 在驱动中创建 binder_ref,引用 binder_node 。binder_ref.desc = 1,2,3... ;在用户态创建服务链表(name,handle),handle 指的是前面的 binder_ref.desc

        3. client 向 service_manger 查询服务,传 name

        4. service_manger 返回 handle 给驱动程序

        5. 驱动程序在 service_manger 的 binder_ref 红黑树中根据 handle 找到 binder_ref,再根据 binder_ref.node 找到 binder_node,最后给 client 创建新的 binder_ref(它的 desc 从 1 开始)。驱动返回 desc 给 client,它即为 handle

        6. client:驱动根据 handle 找到 binder_ref,根据 binder_ref 找到 binder_node,最后根据 binder_node 找到 server 进程。

    下来我们来看看数据传输过程(进程切换)

        client 到 server ,是先写后读:

            1. client 构造数据,调用 ioctl 发数据;

            2. 驱动里根据 handle 找到 server 进程;

            3. 把数据放入进程的 binder_proc.todo;

            4. 休眠;

            5. 被唤醒;

            6. 从 todo 链表中取出数据,返回用户空间。

        server端,先读后写:

            1. 读数据休眠;

            2. 被唤醒;

            3. 从 todo 链表中取出数据,返回用户空间;

            4. 处理数据;

            5. 把结果写给 client,也就是放入 client 的 binder_proc.todo 链表,唤醒 client。

        那么一般情况下,数据是如何进行复制的呢?一般方法,需要 2 次复制。

            1. client 构造数据;

            2. 驱动:copy_from_user

            3. server:3.1 驱动,copy_to_user

                             3.2 用户态处理

        binder复制数据的方法是只需 1 次复制。

            1. server 进行 mmap 映射,用户态可以直接访问驱动中的某块内存。

            2. client 构造数据,驱动:copy_from_user

            3. server 可以在用户态直接使用数据。

        但是值得注意的是:在 binder 方法中,从 test_client 到 test_server 端有个数据需复制 2 次。在 ioctl 时,binder_write_read 结构体先 copy_from_user 到某个内存局部变量,然后再 copy_to_user 到 test_server 端。别的数据都是从 test_cliet 端 copy_from_user 到内核内存,然后 test_server 端直接通过 mmap 可以访问到内核内存,不用经过 copy_to_user 复制。因此 binder 系统在进行通信时效率能提高一倍。

        接下来我们来看看服务注册过程,我们先来看看 binder 的驱动框架。我们在 binder_init 函数中看到它是使用 misc_register 来注册的,说明它是 misc 设备驱动。通过注册 binder_miscdev 结构体以达到调用 binder_fops 结构体,在 binder_fops 结构体中就含有 binder 驱动各种操作的入口函数。具体代码如下

static int __init binder_init(void) {     int ret;     binder_deferred_workqueue = create_singlethread_workqueue("binder");     if (!binder_deferred_workqueue)         return -ENOMEM;     binder_debugfs_dir_entry_root = debugfs_create_dir("binder", NULL);     if (binder_debugfs_dir_entry_root)         binder_debugfs_dir_entry_proc = debugfs_create_dir("proc",                          binder_debugfs_dir_entry_root);     ret = misc_register(&binder_miscdev);     if (binder_debugfs_dir_entry_root) {         debugfs_create_file("state",                     S_IRUGO,                     binder_debugfs_dir_entry_root,                     NULL,                     &binder_state_fops);         debugfs_create_file("stats",                     S_IRUGO,                     binder_debugfs_dir_entry_root,                     NULL,                     &binder_stats_fops);         debugfs_create_file("transactions",                     S_IRUGO,                     binder_debugfs_dir_entry_root,                     NULL,                     &binder_transactions_fops);         debugfs_create_file("transaction_log",                     S_IRUGO,                     binder_debugfs_dir_entry_root,                     &binder_transaction_log,                     &binder_transaction_log_fops);         debugfs_create_file("failed_transaction_log",                     S_IRUGO,                     binder_debugfs_dir_entry_root,                     &binder_transaction_log_failed,                     &binder_transaction_log_fops);     }     return ret; }

        binder_miscdev 代码如下

static struct miscdevice binder_miscdev = {     .minor = MISC_DYNAMIC_MINOR,     .name = "binder",     .fops = &binder_fops };

        binder_fops 代码如下

static const struct file_operations binder_fops = {     .owner = THIS_MODULE,     .poll = binder_poll,     .unlocked_ioctl = binder_ioctl,     .mmap = binder_mmap,     .open = binder_open,     .flush = binder_flush,     .release = binder_release, };

        在 service_manger 中,打开 binder driver,紧接着 ioctl,最后再 mmap。代码如下

struct binder_state *binder_open(size_t mapsize) {     struct binder_state *bs;     struct binder_version vers;     bs = malloc(sizeof(*bs));     if (!bs) {         errno = ENOMEM;         return NULL;     }     bs->fd = open("/dev/binder", O_RDWR);     if (bs->fd < 0) {         fprintf(stderr,"binder: cannot open device (%s)\n",                 strerror(errno));         goto fail_open;     }     if ((ioctl(bs->fd, BINDER_VERSION, &vers) == -1) ||         (vers.protocol_version != BINDER_CURRENT_PROTOCOL_VERSION)) {         fprintf(stderr, "binder: driver version differs from user space\n");         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;     }     return bs; fail_map:     close(bs->fd); fail_open:     free(bs);     return NULL; }

        做完这些操作后,service_manger 便会进入到 binder_loop 循环中。在 binder_loop 函数中,readbuf 中存储的是 BC_ENTER_LOOPER,接着 ioctl BINDER_WRITE_READ,再进行 binder_parse 解析。代码如下

void binder_loop(struct binder_state *bs, binder_handler func) {     int res;     struct binder_write_read bwr;     uint32_t readbuf[32];     bwr.write_size = 0;     bwr.write_consumed = 0;     bwr.write_buffer = 0;     readbuf[0] = BC_ENTER_LOOPER;     binder_write(bs, readbuf, sizeof(uint32_t));     for (;;) {         bwr.read_size = sizeof(readbuf);         bwr.read_consumed = 0;         bwr.read_buffer = (uintptr_t) 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, (uintptr_t) readbuf, bwr.read_consumed, func); // 解析数据         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_write 中传入了 BC_ENTER_LOOPER,看看它做的是那些事情,代码如下

int binder_write(struct binder_state *bs, void *data, size_t len) {     struct binder_write_read bwr;     int res;     bwr.write_size = len;     bwr.write_consumed = 0;     bwr.write_buffer = (uintptr_t) data;     bwr.read_size = 0;     bwr.read_consumed = 0;     bwr.read_buffer = 0;     res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);     if (res < 0) {         fprintf(stderr,"binder_write: ioctl failed (%s)\n",                 strerror(errno));     }     return res; }

        我们看到它先是构造了 binder_write_read 结构体,再通过 binder_ioctl 函数发送了  BINDER_WRITE_READ 指令。我们再去 binder_ioctl 函数中看看 BINDER_WRITE_READ 操作做了哪些事情。代码如下

static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) {     int ret;     struct binder_proc *proc = filp->private_data;     struct binder_thread *thread;     unsigned int size = _IOC_SIZE(cmd);     void __user *ubuf = (void __user *)arg;     /*printk(KERN_INFO "binder_ioctl: %d:%d %x %lx\n",             proc->pid, current->pid, cmd, arg);*/     ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);     if (ret)         return ret;     binder_lock(__func__);     thread = binder_get_thread(proc);     if (thread == NULL) {         ret = -ENOMEM;         goto err;     }     switch (cmd) {     case BINDER_WRITE_READ: {         struct binder_write_read bwr;         if (size != sizeof(struct binder_write_read)) {             ret = -EINVAL;             goto err;         }         if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {             ret = -EFAULT;             goto err;         }         binder_debug(BINDER_DEBUG_READ_WRITE,                  "binder: %d:%d write %ld at %08lx, read %ld at %08lx\n",                  proc->pid, thread->pid, bwr.write_size, bwr.write_buffer,                  bwr.read_size, bwr.read_buffer);         if (bwr.write_size > 0) {             ret = binder_thread_write(proc, thread, (void __user *)bwr.write_buffer, bwr.write_size, &bwr.write_consumed);             if (ret < 0) {                 bwr.read_consumed = 0;                 if (copy_to_user(ubuf, &bwr, sizeof(bwr)))                     ret = -EFAULT;                 goto err;             }         }         if (bwr.read_size > 0) {             ret = binder_thread_read(proc, thread, (void __user *)bwr.read_buffer, bwr.read_size, &bwr.read_consumed, filp->f_flags & O_NONBLOCK);             if (!list_empty(&proc->todo))                 wake_up_interruptible(&proc->wait);             if (ret < 0) {                 if (copy_to_user(ubuf, &bwr, sizeof(bwr)))                     ret = -EFAULT;                 goto err;             }         }         binder_debug(BINDER_DEBUG_READ_WRITE,                  "binder: %d:%d wrote %ld of %ld, read return %ld of %ld\n",                  proc->pid, thread->pid, bwr.write_consumed, bwr.write_size,                  bwr.read_consumed, bwr.read_size);         if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {             ret = -EFAULT;             goto err;         }         break;     }     case BINDER_SET_MAX_THREADS:         if (copy_from_user(&proc->max_threads, ubuf, sizeof(proc->max_threads))) {             ret = -EINVAL;             goto err;         }         break;     case BINDER_SET_CONTEXT_MGR:         if (binder_context_mgr_node != NULL) {             printk(KERN_ERR "binder: BINDER_SET_CONTEXT_MGR already set\n");             ret = -EBUSY;             goto err;         }         ret = security_binder_set_context_mgr(proc->tsk);         if (ret < 0)             goto err;         if (binder_context_mgr_uid != -1) {             if (binder_context_mgr_uid != current->cred->euid) {                 printk(KERN_ERR "binder: BINDER_SET_"                        "CONTEXT_MGR bad uid %d != %d\n",                        current->cred->euid,                        binder_context_mgr_uid);                 ret = -EPERM;                 goto err;             }         } else             binder_context_mgr_uid = current->cred->euid;         binder_context_mgr_node = binder_new_node(proc, NULL, NULL);         if (binder_context_mgr_node == NULL) {             ret = -ENOMEM;             goto err;         }         binder_context_mgr_node->local_weak_refs++;         binder_context_mgr_node->local_strong_refs++;         binder_context_mgr_node->has_strong_ref = 1;         binder_context_mgr_node->has_weak_ref = 1;         break;     case BINDER_THREAD_EXIT:         binder_debug(BINDER_DEBUG_THREADS, "binder: %d:%d exit\n",                  proc->pid, thread->pid);         binder_free_thread(proc, thread);         thread = NULL;         break;     case BINDER_VERSION:         if (size != sizeof(struct binder_version)) {             ret = -EINVAL;             goto err;         }         if (put_user(BINDER_CURRENT_PROTOCOL_VERSION, &((struct binder_version *)ubuf)->protocol_version)) {             ret = -EINVAL;             goto err;         }         break;     default:         ret = -EINVAL;         goto err;     }     ret = 0; err:     if (thread)         thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN;     binder_unlock(__func__);     wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);     if (ret && ret != -ERESTARTSYS)         printk(KERN_INFO "binder: %d:%d ioctl %x %lx returned %d\n", proc->pid, current->pid, cmd, arg, ret);     return ret; }

        我们看到先是构造了一个 binder_write_read 结构体,然后利用 copy_from_user 函数将用户态的数据拷贝至内核(驱动)中。如果有需要给线程中写入数据,便利用 binder_thread_write 写进线程中,同理,读操作也是如此。最后再将 binder_write_read 结构体写回到用户层。对于所有的读操作,数据头都是 BR_NOOP。那么对于这种数据头的处理,binder_parse 函数是直接 break,做休眠处理。

        对于 test_server 先是 binder_open,也就是 打开 binder driver,紧接着 ioctl,最后再 mmap 那一套。然后 while 循环,如果我们传入的是 lookup,他便会调用 svcmgr_lookup 获取服务;如果是 publish,它便会调用 svcmgr_publish 注册服务。

        一般情况是 test_server 先通过 binder_thread_write 函数发送 BC_TRANSACTION,接着便是调用 binder_thread_read 函数来得到一个 BR_NOOP,等待休眠。然后 service_manger 通过 binder_thread_read 获得 BR_TRANSACTION,再通过 binder_thread_write 发送一个 BC_REPLY,最后 test_server 通过 binder_thread_read 获得 BR_REPLY。

        我们重点来讲下 binder_thread_write 函数的 BC_TRANSACTION:

            1. 构造数据:

                a. 构造 binder_io;

                b. 转为 binder_transaction_data;

                c. 放入 binder_write_read 结构体中。

            2. 通过 ioctl 发送数据;

            3. 进去驱动。binder_ioctl 把数据放入 service_manger 进程的 todo 链表,并唤醒他。

                a. 根据 handle 找到目的进程 service_manger(之前 mmap 映射的空间);

                b. 把数据 copy_from_user,放入 mmap 的空间;

                c. 处理 offset 数据,flat_binder_object: 构造 binder_node 给 test_server,构造 binder_ref 给 service_manger,增加引用计数。

                d. 唤醒目的进程。

        后面就一直是处于 test_server 和 service_manger 进程的 binder_thread_write 和 binder_thread_read 的来回作用中。

        在这其中所涉及的 cmd 中,只有 BC_TRANSACTION,BR_TRANSACTION,BC_REPLY 和 BR_REPLY 是涉及两进程的,其他所有的 cmd 只是 APP 和驱动的交互,用于改变/报告状态。

        我们来总结服务的注册过程和获取过程。

        服务注册过程如下:

            1. 构造数据,包括 name = “hello” 和 flat_binder_node 结构体;

            2. 发送 ioctl;

            3. 根据 handle = 0 找到 service_manger 进程,再把数据放到 service_manger 的 todo 链表中;

            4. 构造结构体。binder_node 给源进程,binder_ref 给目的进程;

            5. 唤醒 service_manger;

            6. 调用 ADD_SERVICE 函数;

            7. 在 svclist 中创建一项(主要是 name =“hello”和 handle);

            8. binder_ref 引用服务,此时的 node 便指向 binder_node。

        上面的 1 和 2 是在 test_server 的用户态完成的,3 4 5 是在 test_server 的内核态完成的;6 7 是在 service_manger 的用户态完成的,8 是在 service_manger 的内核态完成的。

        服务获取过程如下:

            1. 构造数据(name = “hello”);

            2. 通过 ioctl 发送数据给 service_manger,handle = 0;

            3. 根据 handle = 0,找到 service_manger,把数据放入他的 todo 链表;

            4. 唤醒 service_manger;

            5. service_manger 内核态返回数据;

            6. service_manger 用户态取出数据,得到 hello 服务;

            7. 在 svclist 链表里根据 hello 服务名 找到一项,得到 handle = 1;

            8. 用 ioctl 把 handle 发给驱动;

            9. service_manger 在内核态的 refs_by_desc 树中,根据 handle = 1 找到 binder_ref,进而找到 hello 服务的 binder_node;

            10. 为 test_client 创建 binder_ref,把handle = 1 放入 test_cient 的 todo 链表;

            11. 唤醒 tes_client;

            12. test_client 内核态返回 handle = 1;

            13. test_client 用户态得到 handle = 1,进而 binder_ref.desc = 1,它中的 node 便对应于前面的 hello 服务。

        上面的 1 2 13 是在 test_client 的用户态完成的,3 4 12 是在 test_client 的内核态完成的;6 7 8 是在 service_manger 的用户态完成的,5 9 10 11 是在 service_manger 的内核态完成的。

        下面我们来看看服务使用过程,跟注册和获取过程类似

            1. 获得 “hello”服务,handle = 1;

            2. 构造数据,code 是指调用哪个函数,构造参数;

            3. 通过 ioctl 发送数据(先写后读);

            4. binder_ioctl,根据 handle 找到目的进程;即 test_server;

            5. 把数据放入 test_server 的 todo 链表;

            6. 唤醒 test_server,然后再 binder_thread_read 中休眠;

            7. test_server 内核态被唤醒,返回数据到 test_server 用户态;

            8. test_server 用户态取出数据,根据 code 和 参数 调用函数;

            9. 用返回值构造数据;

            10. 通过 ioctl 回复 REPLY;

            11. test_server 内核态找出要回复的进程,即 test_client;

            12. 把数据放入 test_client 的 todo 链表;

            13. 唤醒 test_client;

            14. 内核态被唤醒,把数据犯规给用户空间;

            15. test_client 用户态取出返回值,至此使用过程完成。

        上面的 1 2 3 15 是在 test_client 的用户态完成的,4 5 6 14 是在 test_client 的内核态完成的;8 9 10 是在 test_server 的用户态完成的,7 11 12 13 是在 test_server 的内核态完成的。

感谢你能够认真阅读完这篇文章,希望小编分享的“Android系统中Binder子系统有什么用”这篇文章对大家有帮助,同时也希望大家多多支持亿速云,关注亿速云行业资讯频道,更多相关知识等着你来学习!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI