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.
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:
- Int pid; //The process ID of the current process's group leader
- Struct task_struct *tsk; //Save the task struck of the current process
- Struct list_head todo; //The transaction to be completed
- 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.
Good
ReplyDelete