In the previous article, in the source code analysis of the android anonymous shared memory ashmem (anonymous shared memory) driver, we systematically introduced the implementation principle of the android anonymous shared memory, this article focuses on how it assists the memory management system in effectively managing memory. in the previous article, the android system anonymous shared memory ashmem (anonymous shared memory) in brief introduction and learning plan, we also mentioned that the Android system anonymously shares memory. Another feature is that the binder inter-process communication mechanism is used to achieve inter-process sharing. In this article, this section describes in detail how the Android system uses the binder inter-process communication mechanism for anonymous shared memory to achieve inter-process sharing.
Since the principle of Interprocess sharing exists in the anonymous sharing of the Android system involves knowledge about the communication mechanism between processes in the binder system, it is hoped that before reading this article, it is best to have a certain understanding of the binder inter-process communication mechanism in the Android system. For details, refer to the introduction and learning plan of the Binder Mechanism in the android inter-process communication (IPC.
In the brief introduction to the anonymous shared memory ashmem (anonymous shared memory) in the Android system and the learning plan, we give an example to briefly introduce the anonymous shared memory mechanism of the android System and Its Usage. In this article, we will continue to use this instance to demonstrate how the Android system uses the binder inter-process communication mechanism for anonymous shared memory to achieve inter-process sharing. In order to facilitate the description, combined with the previous knowledge about the communication mechanism between binder processes, we use the following sequence diagram to summarize the process of transferring file descriptors of anonymous shared memory files in this instance between processes:
Here, we need to pay attention to the dotted box section, which implements the method of sharing the same open file in the binder driver in two processes. We know that in Linux, the file descriptor is actually an integer. Each process has an array of open files in the kernel space. The integer value of this file descriptor is used to index this array. Moreover, this file descriptor is only valid in this process. That is to say, in different processes, the same file descriptor value may indicate different open files. Therefore, when a file descriptor is transmitted between processes, a file descriptor cannot be transmitted from one process to another. A conversion must be performed in the middle, so that the file description is valid in the target process, and it is consistent with the open file corresponding to the file descriptor of the source process, so as to ensure sharing.
In the article about how service manager becomes the binder daemon of the android inter-process communication (IPC) mechanism, we introduce the data structure of the binder object for transmission, struct flat_binder_object, it is defined in kernel/common/Drivers/staging/Android/binder. h file:
/* * This is the flattened representation of a Binder object for transfer * between processes. The 'offsets' supplied as part of a binder transaction * contains offsets into the data where these structures occur. The Binder * driver takes care of re-writing the structure type and data as it moves * between processes. */struct flat_binder_object {/* 8 bytes for large_flat_header. */unsigned longtype;unsigned longflags;/* 8 bytes of data. */union {void*binder;/* local object */signed longhandle;/* remote object */};/* extra data associated with local object */void*cookie;};
The field type is an enumeration type, and its value range is:
enum {BINDER_TYPE_BINDER= B_PACK_CHARS('s', 'b', '*', B_TYPE_LARGE),BINDER_TYPE_WEAK_BINDER= B_PACK_CHARS('w', 'b', '*', B_TYPE_LARGE),BINDER_TYPE_HANDLE= B_PACK_CHARS('s', 'h', '*', B_TYPE_LARGE),BINDER_TYPE_WEAK_HANDLE= B_PACK_CHARS('w', 'h', '*', B_TYPE_LARGE),BINDER_TYPE_FD= B_PACK_CHARS('f', 'd', '*', B_TYPE_LARGE),};
The type of the binder object we will introduce here is binder_type_fd. The value of the file descriptor to be transmitted is stored in the handle domain.
In the source code analysis of the server startup process in the binder of the inter-process communication (IPC) mechanism of the Android system, we detail the complete process of inter-process communication and transmission of the binder object, I will not go into detail here. You can refer to any reading that you are interested in. Here, we only focus on the processing logic of file descriptor-Type binder objects in the binder driver.
The binder object of file descriptor type is implemented in the binder_transact function in the binder driver. This function is defined in the kernel/common/Drivers/staging/Android/binder. c file:
static voidbinder_transaction(struct binder_proc *proc, struct binder_thread *thread,struct binder_transaction_data *tr, int reply){struct binder_transaction *t;struct binder_work *tcomplete;size_t *offp, *off_end;struct binder_proc *target_proc;struct binder_thread *target_thread = NULL;struct binder_node *target_node = NULL;struct list_head *target_list;wait_queue_head_t *target_wait;struct binder_transaction *in_reply_to = NULL;struct binder_transaction_log_entry *e;uint32_t return_error;......offp = (size_t *)(t->buffer->data + ALIGN(tr->data_size, sizeof(void *)));......off_end = (void *)offp + tr->offsets_size;for (; offp < off_end; offp++) {struct flat_binder_object *fp;......fp = (struct flat_binder_object *)(t->buffer->data + *offp);switch (fp->type) {......case BINDER_TYPE_FD: {int target_fd;struct file *file;if (reply) {if (!(in_reply_to->flags & TF_ACCEPT_FDS)) {binder_user_error("binder: %d:%d got reply with fd, %ld, but target does not allow fds\n",proc->pid, thread->pid, fp->handle);return_error = BR_FAILED_REPLY;goto err_fd_not_allowed;}} else if (!target_node->accept_fds) {binder_user_error("binder: %d:%d got transaction with fd, %ld, but target does not allow fds\n",proc->pid, thread->pid, fp->handle);return_error = BR_FAILED_REPLY;goto err_fd_not_allowed;}file = fget(fp->handle);if (file == NULL) {binder_user_error("binder: %d:%d got transaction with invalid fd, %ld\n",proc->pid, thread->pid, fp->handle);return_error = BR_FAILED_REPLY;goto err_fget_failed;}target_fd = task_get_unused_fd_flags(target_proc, O_CLOEXEC);if (target_fd < 0) {fput(file);return_error = BR_FAILED_REPLY;goto err_get_unused_fd_failed;}task_fd_install(target_proc, target_fd, file);if (binder_debug_mask & BINDER_DEBUG_TRANSACTION)printk(KERN_INFO " fd %ld -> %d\n", fp->handle, target_fd);/* TODO: fput? */fp->handle = target_fd;} break;......}}......}
Here, we will first clarify the scenario of getting the file descriptor of anonymous shared memory files in the Android system's brief introduction and learning plan in anonymous shared memory. The anonymous shared memory file is created in the server process. The client uses the imemoryservice. getfiledescriptor gets the file descriptor of the anonymous shared memory file created by the server process. When the server process returns this file descriptor, it enters the binder driver, that is, the binder_transact function. Therefore, the current process executing the binder_transact function here is the server process, that is, the source process is the server process, and the target process is the client process, which is the process represented by target_proc.
The binder_transaction function processes the binder object of the file descriptor type in the for loop in the middle.
First, obtain the binder object and save it in the local variable FP:
fp = (struct flat_binder_object *)(t->buffer->data + *offp);
The file descriptor value is saved in FP-> handle, and the open file structure corresponding to this file descriptor is retrieved through the fget function:
file = fget(fp->handle);
The file here is a struct file pointer, which indicates an open file structure. Note: in Linux, open the file structure struct file can be shared among processes, which is different from the file descriptor.
Then obtain an idle file descriptor in the target process:
target_fd = task_get_unused_fd_flags(target_proc, O_CLOEXEC);
Now, in the target process, the open file structure is available, and the file descriptor is available. Next we can associate the file descriptor with the open file structure:
task_fd_install(target_proc, target_fd, file);
Because the binder object is finally returned to the target process, you need to modify the value of FP-> handle, which originally represents the file descriptor in the source process, change the file descriptor of the target process:
fp->handle = target_fd;
In this way, the processing of the binder object of the file descriptor type is complete. After obtaining the file descriptor, the target process can share and open the file with the source process.
So far, the android system's anonymous shared memory uses the binder inter-process communication mechanism to achieve inter-process Sharing learning. The learning of the entire android system's anonymous shared memory mechanism has been completed, I hope it will be helpful to readers. To learn more about the anonymous Memory Sharing Mechanism of the Android system, please return to the brief introduction and learning plan of the anonymous shared memory ashmem (anonymous shared memory) in the Android system.
Lao Luo's Sina Weibo: http://weibo.com/shengyangluo. welcome to the attention!