Android Binder Tutorial [Part Two]: ServiceMananger Startup.

ServiceManager.

The ServiceManager is the main process, which manages all the services of the system. It provides the functionality to register and find the corresponding services. ServiceManager works directly with the binder driver for required IPC.
We will try to analyze the startup process of the ServiceManager, ServiceManager
Let us first look at where the ServiceManager starts. It is in the init.rc script. This script is parsed by the init program.


servicemanager startup

The above command will start the /system/bin/servicemanager executable. The name of the service is also servicemanager, There are a few more attributes of this service which will be discussed later.



Let us analyze its main function of servicemanager:

service_manager.c




















The binder_state structure is as follows:
  • fd describes the file descriptor returned by open /dev/binder.
  • mapped is the starting address of the memory mapped to user space;
  • mapsize is the size of the mapped memory area. 

binder_open opens the binder device file and map it to user space:
Let us look at the binder driver file to analyze the code in drivers/staging/android/binder.c

According to the above definition, the open and mmap methods will eventually call the two function pointers binder_open and binder_mmap inside the file_operations. First, let us look at the binder_open method.


binder_open first constructs a binder_proc data structure, binder_proc saves the context information of the open /dev/binder device process.
Let us take a look at the binder_proc structure:


Some of the important elements in the data structure and their use.

  1.         Int  pid;           //The process ID of the current process's group leader  
  2.         Struct  task_struct *tsk;       //Save the task struck of the current process  
  3.         Struct  list_head todo;       //The transaction to be completed  
  4.         Struct  binder_stats stats;   // current binder status record  
The binder_open method above will initialize the list of todo, wait, etc. in binder_proc, and save the current binder_proc in private_data in /dev/binder to open the file filp to facilitate future access.

Let us now look at the binder_map function.


From the open file private_data extract the current binder_proc structure, and then check the memory map area is greater than 4M, from the previous in the service_manager binder_open (128 * 1024), we know that the memory map size is 128K. Then call get_vm_area to allocate the memory virtual space for the kernel.


Going back to service_manager, It will call binder_become_context_manager to make serviceManager become the manager of binder:



This will be done by BINDER_SET_CONTEXT_MGR command to the above / dev/binder handle opened by ioctl.

The binder_ioctl function first calls binder_get_thread to get the binder thread of the currently invoked operation.

Since this is the first call, it will create a new binder_thread structure, the binder_thread proc set to the current binder_proc structure, pid set to the current process pid, and initialize the wait, todo list, and through the binder_thread structure rb_node binder_thread Join the threads red and black tree in binder_proc.


First initializes some information of the binder_node, and then links the binder_node to the red and black nodes of the binder_proc structure through the rb_node. 
Then increases the binder_context_mgr_node strong/weak reference count in processing the BINDER_SET_CONTEXT_MGR command. 

After processing the BINDER_SET_CONTEXT_MGR command, the looper in binder_thread is set to 0 again. Going back to service_manager, we'll call binder_loop to loop through the client's request.



func is a function pointer that handles the request, which is svcmgr_handler. It calls binder_write send BC_ENTER_LOOPER command to the binder driver, we first look at binder_write implementation.


First declare a binder_write_read structure, binder_write_read is the structure of the data in the user space and kernel space, defined as follows.
binder_write, sends a BINDER_WRITE_READ instruction to the binder driver, with a binder_write_read data structure, which only has write_buffer and write_size, read_size and read_buffer are empty, to see how the binder driver handles this request.

First of all, through the binder_get_thread it finds and returns the processing binder_thread which was set through the previous processing of BINDER_SET_CONTEXT_MGR command.



then copy from_user will copy the userspace binder_write_read structure to kernel space bwr variables, and then determine its write_size and read_size, if they are not 0, call binder_thread_write and binder_thread_read to handle write requests and read requests. From the previous binder_writer function we know that write_szie is not 0 here, so call binder_thread_write to handle the BC_ENTER_LOOP command:




Finally, It removes the BC_ENTER_LOOPER command from the writer_buffer in the binder_write_read data structure, and then set the looper bit of binder_thread to BINDER_LOOPER_STATE_ENTERED, indicating that it has entered the looper loop. After processing the BC_ENTER_LOOPER command, send the BINDER_WRITE_READ to the binder driver in the binder_looper method. This time with the binder_write_read parameter, only the read_size is not 0, and the write_size is 0. We know through the above knowledge that the binder_thread_read will be called to handle.

Comments

Post a Comment

Popular posts from this blog

Android Audio Tutorial [Part Three] : AudioFlinger Introduction and Initialization

Android External Storage Support: Volume Daemon (vold) Architecture

Android Audio Tutorial [Part One] : Introduction