How does Service Manager Start?
Why should we talk about Service Manager and mediaserver startup? Because we will talk about the Camera process later.
You will use related knowledge points. Considering the structure of the article and the reading experience, we decided to separate the two parts,
Targeted analysis. For the Binder section, I only write the analysis based on my own understanding, but did not grasp the log in practice.
To confirm the method, how to add log in the relevant process, please kindly advise !!
I have explained how to start the service in init. rc and used zygote as an example. For more information, see
Reading Notes for an in-depth understanding of Android volume 1 (1) -- Analysis of Android Init from Main to service start
Service Manager is started in the same way. Let's take a look at the related fragments in init. rc:
service servicemanager /system/bin/servicemanager class core user system group system critical onrestart restart zygote onrestart restart media onrestart restart surfaceflinger onrestart restart drm
Well, the first sentence is: service servicemanager/system/bin/servicemanager
Where is the code? Where is the entrance?
Where is the source code of the servicemanager program located? Find Makefile !! How to find it? Search servicemanager for the directory,
File? Indeed, this is the case. Let's see how frameworks/base/cmds/servicemanager/Android. mk is written?
include $(CLEAR_VARS)LOCAL_SHARED_LIBRARIES := liblogLOCAL_SRC_FILES := service_manager.c binder.cLOCAL_MODULE := servicemanagerinclude $(BUILD_EXECUTABLE)
I'm so touched. From LOCAL_MODULE to servicemanager, we know it is what we are looking !! This directory is involved
Service_manager.c and binder. c (one header file with binder. h ).
The first step is to find the main function, the entry function of the program. Wow, I found it. I'm so excited to have it...
int main(int argc, char **argv){ struct binder_state *bs; void *svcmgr = BINDER_SERVICE_MANAGER; bs = binder_open(128*1024); if (binder_become_context_manager(bs)) { ALOGE("cannot become context manager (%s)\n", strerror(errno)); return -1; } svcmgr_handle = svcmgr; binder_loop(bs, svcmgr_handler); return 0;}
Variable value: No matter what it is for the time being. Let's first look at what the called function has done.
Describe binder_open
struct binder_state *binder_open(unsigned mapsize){ struct binder_state *bs; bs = malloc(sizeof(*bs)); if (!bs) { errno = ENOMEM; return 0; } bs->fd = open("/dev/binder", O_RDWR); if (bs->fd < 0) { fprintf(stderr,"binder: cannot open device (%s)\n", strerror(errno)); 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; } /* TODO: check version */ return bs;fail_map: close(bs->fd);fail_open: free(bs); return 0;}
Enable the/dev/binder device and call mmap to map the device to the memory (128*1024) bytes. But here open,
Mmap actually calls the open and mmap functions registered by the binder driver. Take open as an example.
Binder_open function in kernel/drivers/staging/android/binder. c.
static int binder_open(struct inode *nodp, struct file *filp){struct binder_proc *proc;binder_debug(BINDER_DEBUG_OPEN_CLOSE, "binder_open: %d:%d\n", current->group_leader->pid, current->pid);proc = kzalloc(sizeof(*proc), GFP_KERNEL);if (proc == NULL)return -ENOMEM;get_task_struct(current);proc->tsk = current;INIT_LIST_HEAD(&proc->todo);init_waitqueue_head(&proc->wait);proc->default_priority = task_nice(current);#ifdef RT_PRIO_INHERITproc->default_rt_prio = current->rt_priority;proc->default_policy = current->policy;#endifbinder_lock(__func__);binder_stats_created(BINDER_STAT_PROC);hlist_add_head(&proc->proc_node, &binder_procs);proc->pid = current->group_leader->pid;INIT_LIST_HEAD(&proc->delivered_death);filp->private_data = proc;binder_unlock(__func__);if (binder_debugfs_dir_entry_proc) {char strbuf[11];snprintf(strbuf, sizeof(strbuf), "%u", proc->pid);proc->debugfs_entry = debugfs_create_file(strbuf, S_IRUGO,binder_debugfs_dir_entry_proc, proc, &binder_proc_fops);}return 0;}
Binder_become_context_manager
int binder_become_context_manager(struct binder_state *bs){ return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);}
Originally, the command BINDER_SET_CONTEXT_MGR was sent to the/dev/binder device through ioctl. Basic Linux Driver knowledge
If the file operation function pointer array registered by the driver of the device contains the specified ioctl function,
The ioctl function will be the corresponding registration function.
The binder-related code is located in the kernel/drivers/staging/android directory. In the Binder. c directory, we can see
This is the ioctl function of the binder_ioctl device we are looking. How does the Code prove this?
Search binder_ioctl in this file. We can see that:
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,};static struct miscdevice binder_miscdev = {.minor = MISC_DYNAMIC_MINOR,.name = "binder",.fops = &binder_fops};
Are you familiar with this stuff? Yes. In many cases about drivers, we will see examples of character device drivers.
There will be module_init/module_exit. The module insertion and removal, registration and cancellation of character devices, and
File operation Array. The array specifies various operation functions of the device file, such as open, ioctl, and release.
The same is true here. Another question is, where is the device driver entry (the function executed during insert module? Search down
The above binder_miscdev to see where the device is registered. Originally in the binder_init function:
ret = misc_register(&binder_miscdev);
Who calls binder_init?
device_initcall(binder_init);#define device_initcall(fn)module_init(fn)/* Each module must use one module_init(). */#define module_init(initfn)\static inline initcall_t __inittest(void)\{ return initfn; }\int init_module(void) __attribute__((alias(#initfn)));
Finally, the binder_init was called in init_module. Okay, tracing is over. Let's look back.
Let's see what BINDER_SET_CONTEXT_MGR has done in binder_ioctl.
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);*/trace_binder_ioctl(cmd, arg);ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);if (ret)goto err_unlocked;binder_lock(__func__);thread = binder_get_thread(proc);if (thread == NULL) {ret = -ENOMEM;goto err;}
case BINDER_SET_CONTEXT_MGR:binder_context_mgr_node = binder_new_node(proc, NULL, NULL);if (binder_context_mgr_node == NULL) {ret = -ENOMEM;goto err;}#ifdef BINDER_MONITORstrcpy(binder_context_mgr_node->name, "servicemanager");#endifbinder_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;
First, let's take a look at what binder_new_node has done.
static struct binder_node *binder_new_node(struct binder_proc *proc, void __user *ptr, void __user *cookie){struct rb_node **p = &proc->nodes.rb_node;struct rb_node *parent = NULL;struct binder_node *node;while (*p) {parent = *p;node = rb_entry(parent, struct binder_node, rb_node);if (ptr < node->ptr)p = &(*p)->rb_left;else if (ptr > node->ptr)p = &(*p)->rb_right;elsereturn NULL;}node = kzalloc(sizeof(*node), GFP_KERNEL);if (node == NULL)return NULL;binder_stats_created(BINDER_STAT_NODE);rb_link_node(&node->rb_node, parent, p);rb_insert_color(&node->rb_node, &proc->nodes);node->debug_id = ++binder_last_id;node->proc = proc;node->ptr = ptr;node->cookie = cookie;node->work.type = BINDER_WORK_NODE;INIT_LIST_HEAD(&node->work.entry);INIT_LIST_HEAD(&node->async_todo);binder_debug(BINDER_DEBUG_INTERNAL_REFS, "binder: %d:%d node %d u%p c%p created\n", proc->pid, current->pid, node->debug_id, node->ptr, node->cookie);return node;}
The function and variable name are related to the red/black tree. Search for this node in the red/black tree, and then call rb_link_node and rb_insert_color.
Insert the node to the red/black tree. The debug_id uniquely identifies each created binder node, the input ptr and cookie.
All are NULL. Create the work. entry and async_todo linked lists for this code. For a more detailed explanation of this clip, you still need some guidance.
#ifdef BINDER_MONITORstrcpy(binder_context_mgr_node->name, "servicemanager");#endif
This sentence is the key. We clearly know that this binder_context_mgr_node is the Service Manager. This global variable
"Binder_context_mgr_node" represents "service manager. Pay attention to this variable in the future !!!
In binder_loop and svcmgr_handler, svcmgr_handle is assigned NULL.
#define BINDER_SERVICE_MANAGER ((void*) 0)void *svcmgr = BINDER_SERVICE_MANAGER;svcmgr_handle = svcmgr;
Let's go back to the topic and see how to write this binder_loop function.
bwr.write_size = 0; bwr.write_consumed = 0; bwr.write_buffer = 0; readbuf[0] = BC_ENTER_LOOPER; binder_write(bs, readbuf, sizeof(unsigned));
int binder_write(struct binder_state *bs, void *data, unsigned len){ struct binder_write_read bwr; int res; bwr.write_size = len; bwr.write_consumed = 0; bwr.write_buffer = (unsigned) 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;}
It can be seen that this binder_write actually sets the write part in the binder_write_read struct, while the read
Some are empty (read_size is 0, read_buffer is NULL), and then the BINDER_WRITE_READ command is sent through ioctl.
case BINDER_WRITE_READ: ......if (copy_from_user(&bwr, ubuf, sizeof(bwr))) { ret = -EFAULT; goto err;}......if (bwr.write_size > 0) {ret = binder_thread_write(proc, thread, (void __user *)bwr.write_buffer, bwr.write_size, &bwr.write_consumed);trace_binder_write_done(ret);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);trace_binder_read_done(ret);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;}}if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {ret = -EFAULT;goto err;}
Since it is a driver, it involves the transmission of kernel space and user space data. Use copy_from_user to copy user space data
In the kernel space (before the driver processes data), copy_to_user copies the data in the kernel space to the user space.
(After the driver processes the data ).
Here, write_size> 0, while read_size is 0. Continue to look at the binder_thread_write function:
case BC_ENTER_LOOPER:thread->looper |= BINDER_LOOPER_STATE_ENTERED;break;
Oh, it turns out that the status of the logoff member with the binder_thread structure is set. The command bc_enter_low.gov.cn
Corresponding. Continue to look at other parts of binder_loop.
for (;;) { bwr.read_size = sizeof(readbuf); bwr.read_consumed = 0; bwr.read_buffer = (unsigned) 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, 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; } }
This endless loop exits only when an error occurs. The first half of bc_enter_logint is binder_write,
Write Data (set command ). Here we will continue to talk about the second half-the binary data (Binder Reply ).
The above binder_write is finished. in the loop here, we can see that read_size is not 0, as shown in
Case BINDER_WRITE_READ: The binder_thread_read function is executed.
if (*consumed == 0) {if (put_user(BR_NOOP, (uint32_t __user *)ptr))return -EFAULT;ptr += sizeof(uint32_t);}
The BR_NOOP (that is, Binder Reply NO OPeraterion) will be put into the user space. By the way
Put_user is different from copy_to_user. The former refers to the basic data type (1 byte, 2 byte, 4 byte, 8 byte)
Copy to user space. The latter can copy data of any length (the parameter contains the length and Data Pointer ).
In this case, the thread_todo linked list should be empty and there is no transaction (I guess )? Then wait_for_proc_work
It should be FALSE. (For return_error, thread-> todo, see binder_get_thread.
It will be called in binder_ioctl)
wait_for_proc_work = thread->transaction_stack == NULL &&list_empty(&thread->todo);
The above should be the status information for setting the binder reply.
thread->looper |= BINDER_LOOPER_STATE_WAITING; ... ...binder_unlock(__func__);
Binder_unlock is directly used here because binder_ioctl has previously called binder_lock.
if (non_block) { if (!binder_has_thread_work(thread))ret = -EAGAIN;}
static int binder_has_thread_work(struct binder_thread *thread){return !list_empty(&thread->todo) || thread->return_error != BR_OK ||(thread->looper & BINDER_LOOPER_STATE_NEED_RETURN);}
To check whether the returned value of the binder_has_thread_work function is true or false, we need to determine the conditions of "|" in the function one by one:
(1) list_empty (& thread-> todo)
This thread-> todo is assigned a value in binder_get_thread.
INIT_LIST_HEAD(&thread->todo);
static inline void INIT_LIST_HEAD(struct list_head *list){list->next = list;list->prev = list;}
static inline int list_empty(const struct list_head *head){return head->next == head;}
Before inserting a node to this linked list, the header node pointer is specified by INIT_LIST_HEAD, which meets the list_empty condition.
(2) return_error and thread-> logoff value in binder_get_thread
thread->looper |= BINDER_LOOPER_STATE_NEED_RETURN;thread->return_error = BR_OK;thread->return_error2 = BR_OK;
Thread-> return_error! = BR_ OK
The judgment result is FALSE, and (thread-> logoff & BINDER_LOOPER_STATE_NEED_RETURN) the judgment
The result is TRUE, so the function returns TRUE.
binder_lock(__func__);thread->looper &= ~BINDER_LOOPER_STATE_WAITING;
Cleared the previously set WAITING status. Let's continue to look at it and we will see the while (1) loop. The related content is as follows:
if (!list_empty(&thread->todo))w = list_first_entry(&thread->todo, struct binder_work, entry);else if (!list_empty(&proc->todo) && wait_for_proc_work)w = list_first_entry(&proc->todo, struct binder_work, entry);else {if (ptr - buffer == 4 && !(thread->looper & BINDER_LOOPER_STATE_NEED_RETURN)) /* no data added */goto retry;break;}
First, the value of list_empty is TRUE. Then, the wait_for_proc_work in else if is determined to be FALSE, so
Will not be executed. The thread in else-> logoff & BINDER_LOOPER_STATE_NEED_RETURN
Is TRUE, So goto retry will not be executed, the following break will be executed, while (1) will exit cyclically.
done:*consumed = ptr - buffer;if (proc->requested_threads + proc->ready_threads == 0 && proc->requested_threads_started < proc->max_threads && (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED)) /* the user-space code fails to */ /*spawn a new thread if we leave this out */) {proc->requested_threads++;binder_debug(BINDER_DEBUG_THREADS, "binder: %d:%d BR_SPAWN_LOOPER\n", proc->pid, thread->pid);if (put_user(BR_SPAWN_LOOPER, (uint32_t __user *)buffer))return -EFAULT;binder_stat_br(proc, thread, BR_SPAWN_LOOPER);}return 0;
Requested_threads, ready_threads, and requested_threads_started are all 0 (no value is assigned ),
The case BINDER_SET_MAX_THREADS of max_threads in binder_ioctl is set.
The open_driver function in frameworks/native/libs/binder/ProcessState. cpp is used to open the binder device:
size_t maxThreads = 15;result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
That is to say, max_threads is 15.
In addition, because the status of thread-> logoff includes BINDER_LOOPER_STATE_ENTERED, the condition is TRUE.
The br_spawn_lon_will be uploaded to the user space, and the status of the binder reply will be set to BR_SPAWN_LOOPER.
OK. Here the binder_ioctl is finished, corresponding to ioctl (bs-> fd, BINDER_WRITE_READ, & bwr) in binder_loop );
After the execution is complete, it is returned to binder_loop. Since the return value of binder_ioctl is 0, binder_parse is executed next.
Let's take a look at the parameters passed in binder_parse:
(1) From bwr. read_buffer = (unsigned) readbuf; we can see that readbuf corresponds to read_buffer, which will be called in ioctl
The process is changed.
binder_thread_read(proc, thread, (void __user *)bwr.read_buffer, bwr.read_size, &bwr.read_consumed
static int binder_thread_read(struct binder_proc *proc, struct binder_thread *thread, void __user *buffer, int size, signed long *consumed, int non_block)
void __user *ptr = buffer + *consumed;void __user *end = buffer + size;
if (put_user(BR_NOOP, (uint32_t __user *)ptr))
The read_buffer corresponds to the binder_thread_read buffer (note that the pointer type is void _ user *), and the pointer ptr is also
Point to this buffer, and the put_user above is to change the content in it. But the problem arises.
(Put_user (BR_SPAWN_LOOPER, (uint32_t _ user *) buffer? When the function comes in, ptr is equal to buffer,
In this case, the previously written BR_NOOP will be removed, but in this case, what is executed in binder_parse will be:
default: ALOGE("parse: OOPS %d\n", cmd); return -1;
This will cause the for Loop in binder_loop to exit. Here, I have to hide it.
The done label statement may be incorrectly analyzed. Where, "requested_threads, ready_threads, requested_threads_started
"0 (no value assigned)" may be incorrect. The statement under if cannot be executed here. Hope you can give me some advice !!
OK, there is only BR_NOOP in read_buffer.
(2) What is bwr. read_consumed? The following two statements will be executed, so read_consumed is sizeof (uint32_t ).
ptr += sizeof(uint32_t);*consumed = ptr - buffer;
(3) What is the passed binder_handler function? Svcmgr_handler !!
int r = 1;uint32_t *end = ptr + (size / 4);case BR_NOOP: break;return r;
Analysis: The above size/4 result is 1, so the while loop is only once, only one binder reply -- BR_NOOP will be processed.
After binder_parse returns 1, it returns to the for loop in binder_loop and continues ioctl and binder_parse.
That is to say, when no command arrives, the REPLY processed here is BR_NOOP.
If you need to reprint, please indicate the source: http://blog.csdn.net/happy08god/article/category/1881463