Binder from Unfamiliar to Familiar (I)

Binder from Unfamiliar to Familiar (ii)

The source code

* The following source code is based on Android 6.0

1. The Binder

  • 1.1 binder_init
kernel/drivers/staging/android/binder.c

//4290 Device driver entry function
device_initcall(binder_init);
/ / 4213
static int __init binder_init(void)
{...// Create a single-threaded work queue named binder
	binder_deferred_workqueue = create_singlethread_workqueue("binder"); .strcpy(device_names, binder_devices_param);

	while ((device_name = strsep(&device_names, ","))) {
		// Initialize the device
		ret = init_binder_device(device_name);
		if (ret)
			goto err_init_binder_device_failed;
	}

	returnret; . }Copy the code

1.1.1 init_binder_device

kernel/drivers/staging/android/binder.c

/ / 4186
static int __init init_binder_device(const char *name)
{
	int ret;
	struct binder_device *binder_device;

	// Allocate memory for binder devices
	binder_device = kzalloc(sizeof(*binder_device), GFP_KERNEL);
	if(! binder_device)return -ENOMEM;
	// Initialize the device
	// The file operation structure of the device is the binder_fops structure
	binder_device->miscdev.fops = &binder_fops;
	// The device number is dynamically allocated
	binder_device->miscdev.minor = MISC_DYNAMIC_MINOR;
	// The device name is binder
	binder_device->miscdev.name = name;

	binder_device->context.binder_context_mgr_uid = INVALID_UID;
	binder_device->context.name = name;

	// misC device registration
	ret = misc_register(&binder_device->miscdev);
	if (ret < 0) {
		kfree(binder_device);
		return ret;
	}
	// Add the hlist node to the list of devices headed by binder_devices
	hlist_add_head(&binder_device->hlist, &binder_devices);

	return ret;
}
Copy the code

1. Allocate memory for binder driver devices

2. Initialize the Binder drivers

3. Add the device to the linked list

  • 1.2 binder_open
kernel/drivers/staging/android/binder.c

/ / 3454
static int binder_open(struct inode *nodp, struct file *filp)
{
	struct binder_proc *proc;
	struct binder_device *binder_dev;

	binder_debug(BINDER_DEBUG_OPEN_CLOSE, "binder_open: %d:%d\n",
		     current->group_leader->pid, current->pid);
	// Allocate memory space to the binder_proc structure in the kernel
	proc = kzalloc(sizeof(*proc), GFP_KERNEL);
	if (proc == NULL)
		return -ENOMEM;
	// Save the current thread's task to binder's task and add the task reference count
	get_task_struct(current);
	proc->tsk = current;
	// Initialize the todo list to store pending requests (Server side)
	INIT_LIST_HEAD(&proc->todo);
	// Initialize the wait queue, which is used to wait for results (client) or requests (server).
	init_waitqueue_head(&proc->wait);
	// Convert the nice value of the current process to the process priority
	proc->default_priority = task_nice(current);
	binder_dev = container_of(filp->private_data, struct binder_device,
				  miscdev);
	proc->context = &binder_dev->context;
	// Add a synchronization lock because Binder supports multithreaded access
	binder_lock(__func__);
	// Number of BINDER_STAT_PROC objects created +1
	binder_stats_created(BINDER_STAT_PROC);
	// Add the proc_node node to the head of the binder_procs queue
	hlist_add_head(&proc->proc_node, &binder_procs);
	/ / process pid
	proc->pid = current->group_leader->pid;
	// Initializes the distributed death notification list
	INIT_LIST_HEAD(&proc->delivered_death);
	// Associate the binder_proc with filp so that the proc can be found by filp for later retrieval in Mmap/IOCtl
	filp->private_data = proc;
	// Release the synchronization lockbinder_unlock(__func__); .return 0;
}
Copy the code

1. Create an instance of the binder_proc structure proc

2. Save the current process information to the Proc instance

3. Link binder_proc into the binder_procs hash list

4. Save the initialized proc to filp->private_data for future use

  • 1.3 binder_mmap
kernel/drivers/staging/android/binder.c

/ / 3355
static int binder_mmap(struct file *filp, struct vm_area_struct *vma/* Describes the virtual address space in user mode. The address space ranges from 0 to 3G*/)
{
	int ret;
	// A contiguous kernel virtual address space. In 32-bit architectures, the address space is between 3G+896M + 8M to 4G
	struct vm_struct *area;
	struct binder_proc *proc = filp->private_data;
	const char *failure_string;
	struct binder_buffer *buffer;

	if(proc->tsk ! = current)return -EINVAL;
	// Ensure that the mapped memory size does not exceed 4M. If it is larger than 4M, change it to 4M
	if((vma->vm_end - vma->vm_start) > SZ_4M) vma->vm_end = vma->vm_start + SZ_4M; .// with the binder_mmAP_lock mutex, since the proc structure will be manipulated later, multithreaded contention can occur to ensure that only one process allocates memory at a time, and concurrent access between multiple processes is guaranteed
	mutex_lock(&binder_mmap_lock);
	If yes, the binder_mmap function is terminated after the synchronization lock is released
	if (proc->buffer) {
		ret = -EBUSY;
		failure_string = "already mapped";
		goto err_already_mapped;
	}
	// Use VM_IOREMAP to allocate a contiguous kernel virtual address space, which is the same size as the process virtual address space. Note that the virtual address space is allocated once, but the physical page is applied and mapped only when necessary
	area = get_vm_area(vma->vm_end - vma->vm_start, VM_IOREMAP);
	// Failed to allocate memory
	if (area == NULL) {
		ret = -ENOMEM;
		failure_string = "get_vm_area";
		goto err_get_vm_area_failed;
	}
	// Records the kernel virtual address in the proc buffer
	proc->buffer = area->addr;
	// Calculate user space and kernel space address offset, address offset = user space virtual memory address - kernel space virtual memory address
	proc->user_buffer_offset = vma->vm_start - (uintptr_t)proc->buffer;
	/ / releases the lockmutex_unlock(&binder_mmap_lock); .// Allocate an array of Pointers to physical pages, the size of which is the equivalent page number of the VMA
	proc->pages = kzalloc(sizeof(proc->pages[0]) * ((vma->vm_end - vma->vm_start) / PAGE_SIZE), GFP_KERNEL);
	if (proc->pages == NULL) {
		ret = -ENOMEM;
		failure_string = "alloc page array";
		goto err_alloc_pages_failed;
	}
	proc->buffer_size = vma->vm_end - vma->vm_start;

	vma->vm_ops = &binder_vm_ops;
	vma->vm_private_data = proc;

	// Allocate a physical page to both kernel space and user process space
	if (binder_update_page_range(proc, 1, proc->buffer, proc->buffer + PAGE_SIZE, vma)) {
		ret = -ENOMEM;
		failure_string = "alloc small buf";
		goto err_alloc_small_buf_failed;
	}
	buffer = proc->buffer;
	INIT_LIST_HEAD(&proc->buffers);
	// Add buffers to the buffers list
	list_add(&buffer->entry, &proc->buffers);
	// This memory is available
	buffer->free = 1;
	// Chain the kernel virtual memory buffer into the Proc buffers and free_buffers lists
	binder_insert_free_buffer(proc, buffer);
	Asynchrony can only use half of the entire address space
	proc->free_async_space = proc->buffer_size / 2;
	barrier();
	proc->files = get_files_struct(current);
	proc->vma = vma;
	proc->vma_vm_mm = vma->vm_mm;

	/*pr_info("binder_mmap: %d %lx-%lx maps %p\n", proc->pid, vma->vm_start, vma->vm_end, proc->buffer); * /
	return 0; . }Copy the code

1.3.1 binder_update_page_range

kernel/drivers/staging/android/binder.c

/ / 576
static int binder_update_page_range(struct binder_proc *proc, int allocate,
				    void *start, void *end,
				    struct vm_area_struct *vma)
{
	void *page_addr;
	unsigned long user_page_addr;
	struct page **page;
	struct mm_struct *mm;.// Allocate =1, allocate=0, allocate=0
	if (allocate == 0)
		gotofree_range; .// Allocate 1 page of physical memory*page = alloc_page(GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO); .// Physical space is mapped to virtual kernel space
		ret = map_kernel_range_noflush((unsigned long)page_addr, PAGE_SIZE, PAGE_KERNEL, page); .// Physical space is mapped to virtual process space
		ret = vm_insert_page(vma, user_page_addr, page[0]); . }Copy the code

1.3.2 binder_insert_free_buffer

kernel/drivers/staging/android/binder.c

/ / 494
static void binder_insert_free_buffer(struct binder_proc *proc, struct binder_buffer *new_buffer)
{
	struct rb_node **p = &proc->free_buffers.rb_node;
	struct rb_node *parent = NULL;
	struct binder_buffer *buffer;
	size_t buffer_size;
	size_tnew_buffer_size; .while(*p) { parent = *p; buffer = rb_entry(parent, struct binder_buffer, rb_node); BUG_ON(! buffer->free);
		// Calculate the size of free memory
		buffer_size = binder_buffer_size(proc, buffer);

		if (new_buffer_size < buffer_size)
			p = &parent->rb_left;
		else
			p = &parent->rb_right;
	}
	rb_link_node(&new_buffer->rb_node, parent, p);
	// Insert buffer into the proc->free_buffers list
	rb_insert_color(&new_buffer->rb_node, &proc->free_buffers);
}
Copy the code

1. Allocate a block of kernel space virtual memory based on the virtual memory size of user space

2. Allocate a block of 4kb (1 page) of physical memory

3. Map the physical memory to the virtual memory of user space and the virtual memory of kernel space

  • 1.4 binder_ioctl
 kernel/drivers/staging/android/binder.c

/ / 3241
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;
	// Read the size of the command
	unsigned int size = _IOC_SIZE(cmd);
	void __user *ubuf = (void __user *)arg;

	/*pr_info("binder_ioctl: %d:%d %x %lx\n", proc->pid, current->pid, cmd, arg); * /

	trace_binder_ioctl(cmd, arg);
	// Go to sleep until the interrupt wakes up
	// If binder_stop_on_user_error < 2, return 0; Otherwise, the call to _wait_EVENT_INTERRUPTIBLE enters an interruptible pending state, and the handler is relinquished,
	Return until wake_up and condition (binder_stop_on_user_error < 2) is true
	ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
	if (ret)
		goto err_unlocked;
	// Get the binder_main_lock lock
	binder_lock(__func__);
	// Select binder_thread from binder_proc based on the pid of the current process, and return binder_thread if the current thread is added to the proc thread queue.
	// If not, create binder_thread and add the current thread to the current proc
	thread = binder_get_thread(proc);
	if (thread == NULL) {
		ret = -ENOMEM;
		goto err;
	}

	switch (cmd) {
		// Read/write commands, data transfer, core logic for Binder IPC communication
	case BINDER_WRITE_READ:
		ret = binder_ioctl_write_read(filp, cmd, arg, thread);
		if (ret)
			goto err;
		break;
		// Sets the maximum number of threads, directly into the PROC structure's max_threads field
		if (copy_from_user(&proc->max_threads, ubuf, sizeof(proc->max_threads))) {
			ret = -EINVAL;
			goto err;
		}
		break;
		// Set the Context Manager, that is, set itself as ServiceManager
	case BINDER_SET_CONTEXT_MGR:
		ret = binder_ioctl_set_ctx_mgr(filp);
		if (ret)
			goto err;
		break;
		//binder thread exits command to release related resources
	case BINDER_THREAD_EXIT:
		binder_debug(BINDER_DEBUG_THREADS, "%d:%d exit\n",
			     proc->pid, thread->pid);
		binder_free_thread(proc, thread);
		thread = NULL;
		break;
		// obtain the binder driver version number, which is 7 for 32-bit version kernel4.4 and 8 for 64-bit version
	case BINDER_VERSION: {
		struct binder_version __user *ver = ubuf;

		if(size ! =sizeof(struct binder_version)) {
			ret = -EINVAL;
			goto err;
		}
		if (put_user(BINDER_CURRENT_PROTOCOL_VERSION,
			     &ver->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) pr_info("%d:%d ioctl %x %lx returned %d\n", proc->pid, current->pid, cmd, arg, ret);
err_unlocked:
	trace_binder_ioctl_done(ret);
	return ret;
}
Copy the code

1.4.1 binder_ioctl_write_read

kernel/drivers/staging/android/binder.c

/ / 3136
static int binder_ioctl_write_read(struct file *filp,
				unsigned int cmd, unsigned long arg,
				struct binder_thread *thread)
{
	int ret = 0;
	struct binder_proc *proc = filp->private_data;
	// Read the size of arg
	unsigned int size = _IOC_SIZE(cmd);
	void __user *ubuf = (void __user *)arg;
	struct binder_write_read bwr;

	if(size ! =sizeof(struct binder_write_read)) {
		ret = -EINVAL;
		goto out;
	}
	// copy user-space data ubuf to kernel-space BWR
	if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
		ret = -EFAULT;
		goto out;
	}
	binder_debug(BINDER_DEBUG_READ_WRITE,
		     "%d:%d write %lld at %016llx, read %lld at %016llx\n",
		     proc->pid, thread->pid,
		     (u64)bwr.write_size, (u64)bwr.write_buffer,
		     (u64)bwr.read_size, (u64)bwr.read_buffer);
	// Indicates that the user process has sent data to the driver. Run binder_thread_write to send data
	if (bwr.write_size > 0) {
		ret = binder_thread_write(proc, thread,
					  bwr.write_buffer,
					  bwr.write_size,
					  &bwr.write_consumed);
		trace_binder_write_done(ret);
		if (ret < 0) {
			// If an error occurs in binder_thread_write, read_consumed is set to 0, indicating that the kernel has no data returned to the process
			bwr.read_consumed = 0;
			// Return the BWR to the user caller, and the BWR will be modified in binder_thread_write
			if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
				ret = -EFAULT;
			gotoout; }}// Indicates that the user address space of the process expects data to be returned to it, and calls binder_thread_read
	if (bwr.read_size > 0) {
		ret = binder_thread_read(proc, thread, bwr.read_buffer,
					 bwr.read_size,
					 &bwr.read_consumed,
					 filp->f_flags & O_NONBLOCK);
		trace_binder_read_done(ret);
		// The process todo queue is not empty and wakes up the thread in the queue
		if(! list_empty(&proc->todo)) wake_up_interruptible(&proc->wait);if (ret < 0) {
			if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
				ret = -EFAULT;
			goto out;
		}
	}
	binder_debug(BINDER_DEBUG_READ_WRITE,
		     "%d:%d wrote %lld of %lld, read return %lld of %lld\n",
		     proc->pid, thread->pid,
		     (u64)bwr.write_consumed, (u64)bwr.write_size,
		     (u64)bwr.read_consumed, (u64)bwr.read_size);
	// copy the kernel space data BWR to user space ubuf
	if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
		ret = -EFAULT;
		goto out;
	}
out:
	return ret;
}
Copy the code

The Binder driver does not provide read/write operations. All data transfer and control are performed through binder_ioctl, which is the core part of the Binder driver. The BINDER_WRITE_READ command is used to transfer data

  • 1.5 Main data structures

1.5.1 File_operations defines file operators associated with corresponding functions of Binder drivers

static const struct file_operations binder_fops = {
	.owner = THIS_MODULE,
	.poll = binder_poll,
	.unlocked_ioctl = binder_ioctl,// called when a 64-bit application is running on a 64-bit kernel or when a 32-bit application is running on a 32-bit kernel
	.compat_ioctl = binder_ioctl,// called when 32-bit applications are running on a 64-bit kernel
	.mmap = binder_mmap,// User-space mmap() operations cause binder_mmap() functions to be called by Binder drivers
	.open = binder_open,// User-space open() calls binder_open() driven by Binder
	.flush = binder_flush,
	.release = binder_release,
};
Copy the code

Binder_proc represents a process that is communicating with a Binder process. Binder drivers create a binder_proc structure for a process that is open /dev/binder. Binder_proc represents a process that is communicating with a Binder process. To record all information about the process and store the structure in a global hash table

kernel/drivers/staging/android/binder.c

/ / 322
struct binder_proc {
	struct hlist_node proc_node;// Process node
	struct rb_root threads;//binder_thread The root node of the red-black tree
	struct rb_root nodes;//binder_node root keyword PTR of the red-black tree
	struct rb_root refs_by_desc;//binder_ref Root node of the red-black tree (handle as key) keyword desc
	struct rb_root refs_by_node;//binder_ref Root node of red-black tree (with PTR as key) keyword node
	int pid;/ / process ID
	struct vm_area_struct *vma; // A pointer to the process's virtual address space
	struct mm_struct *vma_vm_mm; // The entire virtual address space of the process
	struct task_struct *tsk; // The task control module of the corresponding process
	struct files_struct *files; // An array of file structures for the corresponding process
	struct hlist_node deferred_work_node;
	int deferred_work;
	void *buffer; // The starting address of the kernel space
	ptrdiff_t user_buffer_offset;// Address offset between kernel space and user space

	struct list_head buffers;// All buffers
	struct rb_root free_buffers;// Free buffer
	struct rb_root allocated_buffers;// Allocate buffer
	size_t free_async_space;// The amount of free space available for asynchrony

	struct page **pages;// Pointer to physical memory page
	size_t buffer_size;// The size of the mapped kernel space
	uint32_t buffer_free;// Total available memory size
	struct list_head todo; // What the process is going to do
	wait_queue_head_t wait; // Wait for the queue
	struct binder_stats stats;// Binder statistics
	struct list_head delivered_death; // Death notices have been distributed
	int max_threads; // Maximum number of threads
	int requested_threads; // The number of threads requested
	int requested_threads_started; // Number of request threads started
	int ready_threads; // The number of threads ready
	long default_priority; // Default priority
	struct dentry *debugfs_entry;
	struct binder_context *context;// Connect to store binder_node and binder_context_mgr_uid and name
};
Copy the code

Binder_node represents a Binder entity object. Each service component or ServiceManager is described in the Binder driver, which maintains its life cycle through strong and weak references. Find the Service object of the space through Node.

kernel/drivers/staging/android/binder.c

/ / 252
struct binder_node {
	int debug_id; // The node is allocated when it is created. It is globally unique and used for debugging
	struct binder_work work;
	 /** Each binder process is described by a binder_proc, all binder entities are organized by a red-black tree (struct rb_root nodes); Rb_node corresponds to a node */ of nodes
	union {
		struct rb_node rb_node; // The binder node is used properly, and the union node is used to connect the red-black tree
		  // If the process corresponding to the Binder entity object dies, rb_node needs to be removed from the red-black tree when the node is destroyed.
        // If the node is not already referentially cut off, use dead_node to isolate it into another linked list,
        // The node cannot be destroyed until all processes are notified to disreference it
		struct hlist_node dead_node;// The binder node is destroyed, union
	};
	struct binder_proc *proc; // points to the process corresponding to the Binder entity object, described by binder_proc
	 // This Binder entity object may be referenced by multiple Client components at the same time. All references to this entity object are
    // stored in the hash queue refs represents the queue header; These references may belong to different processes that traverse the
    // The hash table can get these Client components reference these objects
	struct hlist_head refs; // All binder reference queues to this node

	/** Reference count * 1. When a Binder entity object requests a Service component to perform a Binder operation. Also, Binder entities will set has_STRONG_REF and has_weak_REF to 1 *2. When a Service component completes an operation requested by a Binder entity, A Binder entity object that requests a Service component to increase or decrease its strong/weak reference count * sets pending_STRONG_ref and Pending_WEAK_ref to 1, and Binder entity objects set them to 0 */ when the Service component completes increasing or decreasing the count
	int internal_strong_refs;// The remote strong reference count actually represents how many binder_refs a binder_node is associated with
	int local_weak_refs;// The number of local weak references
	int local_strong_refs; // Local strong reference count
	binder_uintptr_t ptr; Binder describes the Service component of the user space and corresponds to the BBinder reference of the Service corresponding to the binder entity in the user space
	binder_uintptr_t cookie;// Pointer to user space binder_node, attachment data corresponding to flat_binder_object.cookie Describes the Service component of user space, Binder entities corresponding to the local user space Service (BBinder) address
	unsigned has_strong_ref:1;/ / to take 1 bit
	unsigned pending_strong_ref:1;/ / to take 1 bit
	unsigned has_weak_ref:1;/ / to take 1 bit
	unsigned pending_weak_ref:1;/ / to take 1 bit
	unsigned has_async_transaction:1;/ / to take 1 bit
	 // Indicates whether the Binder entity object can receive interprocess communication data containing the file descriptor. When a process approaches
    // When another process sends data containing file descriptors, Binder opens the same file in the target process
    // Set accept_fds to 0 to prevent the source process from opening files in the target process
	unsigned accept_fds:1;/ / to take 1 bit
	unsigned min_priority:8;// placeholder 8bit minimum thread priority for Binder requests
	struct list_head async_todo;// Asynchronous TODO queue
};
Copy the code

Binder_proc and binder_node: You can think of binder_proc as a process and binder_noder as a Service. Binder_proc has a red-black tree that holds all services created in the process it describes. Each Service is described by a binder_node in the Binder driver.

Async_todo, a step transaction processing, is designed to make way for synchronous interactions and avoid blocking the sending end for long periods of time

Asynchronous transaction definition one-way inter-process communication requirements (as opposed to synchronous transactions), i.e. inter-process communication requests that do not wait for a response Binder drivers consider asynchronous transactions to be of lower priority than synchronous transactions, and at most one asynchronous transaction per Binder entity object will be processed at any one time. Synchronous transactions do not have this limitation. Binder stores transactions in the TODO queue of a thread, binder_thread, indicating that the thread handles the transaction. Each transaction is associated with a Binder entity (Union Target), which represents the transaction’s target processing object and requires the corresponding Service component to process the transaction in the specified thread. If Binder finds that a transaction is an asynchronous transaction, It is stored in an asynchronous transaction of the target Binder object asynC_todo for processing

1.5.4 binder_buffer Kernel buffer used to pass data between processes. Binder drivers manage the memory-mapped address space method buffer~ (buffer+buffer_size), which is divided into segments, each of which is represented by a struct binder_buffer. Each binder_buffer is linked to the buffers representation in struct binder_proc from the lowest address to the highest address by its member entry

kernel/drivers/staging/android/binder.c

/ / 298
struct binder_buffer {
	struct list_head entry; // Address of the buffer entity corresponds to the buffers of the kernel buffer list
	struct rb_node rb_node;  If free=1, rb_node corresponds to a node in free_buffers (kernel buffer) if free! =1, then corresponds to a node in allocated_buffers
				/* by address */
	unsigned free:1; // Indicates whether it is an idle buffer, occupying 1bit
	 /**Binder stores transaction data to a kernel buffer (binder_transaction.buffer) which is then processed by Binder * entity objects (target_node), The target_node sends the contents of the buffer to the corresponding Service component * (proc). After the Service component has processed the transaction, allow_user_free=1 requests Binder to release the kernel buffer */
	unsigned allow_user_free:1;// whether to allow the user to release, placeholder 1bit
	unsigned async_transaction:1; // placeholder 1bit indicates that the transaction is asynchronous; The kernel buffer size for asynchronous transactions is limited to ensure that transactions are placed in the buffer first
	unsigned debug_id:29; / / placeholder - 29

	struct binder_transaction *transaction; // This cache needs to process transactions to relay requests and return results

	struct binder_node *target_node; // Binder entities to be processed for this cache
	/** * Stores communication data. There are two types of data: common data and Binder objects. At the end of the data buffer, there is an offset array that records the offset address of each Binder object in the data buffer
	size_t data_size;// Data buffer size
	size_t offsets_size;// Data offset (which is also the offset position)
	size_t extra_buffers_size;// Additional buffer size
	uint8_t data[0]; // Data address is used to store communication data, data buffer, variable size
};
Copy the code

2. ServiceManager

The ServiceManager is created by parsing the init.rc file when the Android operating system is started. The corresponding executable program ServiceManager is created by the source file Service_manager.c. The process name is Servicemanager. There are two important methods in the ServiceManager: Add_service and check_service: The system service registers its information with the Servicemanager by using add_service. If the service needs to be used, check whether the service exists by using the check_service

  • How do I start the ServiceManager

The entry function to start the ServiceManager is the main() method in service_manager.c.

2.1 the main

frameworks/native/cmds/servicemanager/service_manager.c

/ / 354
int main(int argc, char **argv)
{
    struct binder_state *bs;
    // Open the binder driver and apply for 128K bytes of memory
    bs = (128*1024); .// As a daemon, binder manager
    if (binder_become_context_manager(bs)) {
        ALOGE("cannot become context manager (%s)\n", strerror(errno));
        return - 1; }...// Enter an infinite loop to process requests from the client
    binder_loop(bs, svcmgr_handler);

    return 0;
}
Copy the code

The mian() method does three main things:

  • 2.1.1 binder_open Open theBinder driveTo apply for128 k bytesSize of memory space

But the binder_open is not the binder_open in our binder drivers above, it is in the native layer

frameworks/native/cmds/servicemanager/binder.c

/ / 96
struct binder_state *binder_open(size_t mapsize)
{
    // This structure records all information about binder in service_manager
    struct binder_state *bs;.// Open the binder driver to get the file operator
    bs->fd = open("/dev/binder", O_RDWR); .// the service_manager is set by itself. The size is 128kb
    bs->mapsize = mapsize;
    // Through the system call, mmap memory mapping, mmap must be an integer multiple of page (i.e., 4KB multiple)
    bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0); . }Copy the code
  • 2.1.2 binder_become_context_manager Make it the daemon that manages binder
frameworks/native/cmds/servicemanager/binder.c

/ / 146
int binder_become_context_manager(struct binder_state *bs)
{
    return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
}
Copy the code

Because the file_operations structure defines the file operator associated with the Binder driver’s corresponding function, IOTRL executes the Binder driver’s binder_ioctl function

2.1.2.1 binder_ioctl

kernel/drivers/staging/android/binder.c
/ / 3241
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
// 3277 Set Context Manager, that is, set itself as ServiceManager
case BINDER_SET_CONTEXT_MGR:
    ret = binder_ioctl_set_ctx_mgr(filp);
Copy the code

2.1.2.1.1 binder_ioctl_set_ctx_mgr

kernel/drivers/staging/android/binder.c

/ / 3200
static int binder_ioctl_set_ctx_mgr(struct file *filp)
{
	int ret = 0;
	struct binder_proc *proc = filp->private_data;
	struct binder_context *context = proc->context;
	// Get the valid user ID of the current process
	kuid_t curr_euid = current_euid();
	// Ensure that the mgr_node object is created only once
	if (context->binder_context_mgr_node) {
		pr_err("BINDER_SET_CONTEXT_MGR already set\n");
		ret = -EBUSY;
		goto out;
	}
	/ / check whether the current process Context have permission to perform registration Manager permissions, and the function in the 4.4 kernel direct returns 0. ` kernel/include/Linux/security. H `
	ret = security_binder_set_context_mgr(proc->tsk);
	if (ret < 0)
		goto out;
	// Check whether the existing UID is valid
	if (uid_valid(context->binder_context_mgr_uid)) {
		// Valid but not equal to the valid user ID of the current running thread. That is, threads can only register themselves, and only one thread can be set to Context Manager
		if(! uid_eq(context->binder_context_mgr_uid, curr_euid)) { pr_err("BINDER_SET_CONTEXT_MGR bad uid %d ! = %d\n",
			       from_kuid(&init_user_ns, curr_euid),
			       from_kuid(&init_user_ns,
					 context->binder_context_mgr_uid));
			ret = -EPERM;
			gotoout; }}else {// INVALID_UID is set to a valid user ID for the current process. The Service Manager starts the first registration by going to this branch
		context->binder_context_mgr_uid = curr_euid;
	}
	// Assign a new binder_node to the global binder_context_mgr_node variable
	context->binder_context_mgr_node = binder_new_node(proc, 0.0);
	if(! context->binder_context_mgr_node) { ret = -ENOMEM;goto out;
	}
	// Update the reference count
	context->binder_context_mgr_node->local_weak_refs++;
	context->binder_context_mgr_node->local_strong_refs++;
	context->binder_context_mgr_node->has_strong_ref = 1;
	context->binder_context_mgr_node->has_weak_ref = 1;
out:
	return ret;
}
Copy the code

2.1.2.1.1.1 binder_new_node

static struct binder_node *binder_new_node(struct binder_proc *proc,
					   binder_uintptr_t ptr,
					   binder_uintptr_t cookie)
{
	struct rb_node **p = &proc->nodes.rb_node;
	struct rb_node *parent = NULL;
	struct binder_node *node;
	// The first entry is empty
	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;
		else
			return NULL;
	}
	// Allocate kernel space to the newly created binder_node
	node = kzalloc(sizeof(*node), GFP_KERNEL);
	if (node == NULL)
		return NULL;
	binder_stats_created(BINDER_STAT_NODE);
	// Adds the newly created Node object to the Proc red-black tree
	rb_link_node(&node->rb_node, parent, p);
	rb_insert_color(&node->rb_node, &proc->nodes);
	node->debug_id = ++binder_last_id;
	// Initialize binder_node
	node->proc = proc;
	node->ptr = ptr;
	node->cookie = cookie;
	// Set the type of binder_work
	node->work.type = BINDER_WORK_NODE;
	INIT_LIST_HEAD(&node->work.entry);
	INIT_LIST_HEAD(&node->async_todo);
	binder_debug(BINDER_DEBUG_INTERNAL_REFS,
		     "%d:%d node %d u%016llx c%016llx created\n",
		     proc->pid, current->pid, node->debug_id,
		     (u64)node->ptr, (u64)node->cookie);
	return node;
}
Copy the code
  • 2.1.3 binder_loop Enter infinite loop, processingThe client sideA request sent in
frameworks/native/cmds/servicemanager/binder.c

/ / 372
void binder_loop(struct binder_state *bs, binder_handler func)
{
    int res;
    struct binder_write_read bwr;
    uint32_t readbuf[32];

    // initialize to 0
    bwr.write_size = 0;
    bwr.write_consumed = 0;
    bwr.write_buffer = 0;
    // Read and write the command to process
    readbuf[0] = BC_ENTER_LOOPER;
    // Set the thread's looper state to loop
    binder_write(bs, readbuf, sizeof(uint32_t));

    for (;;) {
        // Not 0, go to binder_thread_read
        bwr.read_size = sizeof(readbuf);
        bwr.read_consumed = 0;
        bwr.read_buffer = (uintptr_t) readbuf;
        // Continuously read data with binder, no data will go to sleep
        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; }}}Copy the code

In the binder_loop function, the thread’s looper status is set by the binder_write function. Then, in the for loop, the corresponding driver’s binder_ioctl function is called, passing the BINDER_WRITE_READ command. Execute the binder_ioctl_write_read function, execute the binder_thread_read function in the read processing of this function, and after a series of logical judgments, Ret = wait_event_freezable_EXCLUSIVE (proc->wait, binder_has_proc_work(proc, thread)); The ServiceManager enters the waiting state

Sequence diagram of binder_driver and ServiceManager interaction:

  • How do I obtain a ServiceManager

Obtaining the ServiceManager is done using the defaultServiceManager() method

2.2 defaultServiceManager

frameworks/native/libs/binder/IServiceManager.cpp

/ / 33
sp<IServiceManager> defaultServiceManager(a)
{
    // Singleton, return if not null
    if(gDefaultServiceManager ! =NULL) return gDefaultServiceManager;
    
    {
        AutoMutex _l(gDefaultServiceManagerLock);
        // The ServiceManager may not be ready when the ServiceManager is created or retrieved
        while (gDefaultServiceManager == NULL) {
            / / create DefaultServiceManager
            gDefaultServiceManager = interface_cast<IServiceManager>(
                ProcessState::self() - >getContextObject(NULL));
            if (gDefaultServiceManager == NULL)
                sleep(1); }}return gDefaultServiceManager;
}
Copy the code
  • 2.2.1 ProcessState: : self ()
frameworks/native/libs/binder/ProcessState.cpp

/ / 70
sp<ProcessState> ProcessState::self(a)
{
    Mutex::Autolock _l(gProcessMutex);
        / / the singleton
    if(gProcess ! =NULL) {
        return gProcess;
    }
    // instantiate ProcessState
    gProcess = new ProcessState;
    return gProcess;
}
Copy the code

2.2.1.1 ProcessState

frameworks/native/libs/binder/ProcessState.cpp

/ / 339
ProcessState::ProcessState(a)// Open the driver
    : mDriverFD(open_driver())...Binders are allocated a virtual address space (1m-8K) with the memory mapping function MMAP to receive transactions
        // BINDER_VM_SIZE ((1*1024*1024) - (4096 *2))
        mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0); . }Copy the code

2.2.1.1.1 open_driver ()

frameworks/native/libs/binder/ProcessState.cpp

/ / 311
static int open_driver(a)
{
    // Open the /dev/binder device and set up an interaction channel with the binder driver of the kernel
    int fd = open("/dev/binder", O_RDWR); .Binder drivers are configured with ioctl to support up to 15 threads
          // DEFAULT_MAX_BINDER_THREADS 15
        size_t maxThreads = DEFAULT_MAX_BINDER_THREADS;
        result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads); .return fd;
}
Copy the code

ProcessState::self() does three main things

1. Enable the Binder driver

2. Set the maximum thread to 15

3. Mmap Set the shared memory size to 1 MB to 8 KB

  • 2.2.2 ProcessState: : getContextObject ()
frameworks/native/libs/binder/ProcessState.cpp

/ / 85
sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
{
     // Obtain the service_manager service with the argument 0
    return getStrongProxyForHandle(0);
}
Copy the code

2.2.2.1 ProcessState: : getStrongProxyForHandle

frameworks/native/libs/binder/ProcessState.cpp

/ / 179
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
    sp<IBinder> result;

    AutoMutex _l(mLock);
    // Find the resource item corresponding to handle
    handle_entry* e = lookupHandleLocked(handle);

    if(e ! =NULL) {
        IBinder* b = e->binder;
        // When the IBinder corresponding to the handle value does not exist or a weak reference is invalid
        if (b == NULL| |! e->refs->attemptIncWeak(this)) {
            if (handle == 0) {
                Parcel data;
                // Test binder readiness by ping
                status_t status = IPCThreadState::self() - >transact(
                        0, IBinder::PING_TRANSACTION, data, NULL.0);
                if (status == DEAD_OBJECT)
                   return NULL;
            }
            // Create a BpBinder object
            b = new BpBinder(handle); 
            e->binder = b;
            if (b) e->refs = b->getWeakRefs(a); result = b; }else {
            result.force_set(b);
            e->refs->decWeak(this); }}return result;
}
Copy the code

2.2.2.1.1 BpBinder

frameworks/native/libs/binder/BpBinder.cpp

/ / 39
BpBinder::BpBinder(int32_t handle)
    : mHandle(handle)
    , mAlive(1),mObitsSent(0),mObituaries(NULL)
{
    ALOGV("Creating BpBinder %p handle %d\n".this, mHandle);
    // Strong and weak reference counts are supported. OBJECT_LIFETIME_WEAK indicates that the life cycle of the target object is controlled by weak Pointers
    extendObjectLifetime(OBJECT_LIFETIME_WEAK);
    // Handle's weak reference to bindle + 1
    IPCThreadState::self() - >incWeakHandle(handle);
}
Copy the code

BpBinder is a Proxy class used by clients to interact with servers. P stands for Proxy. BBinder is the opposite end of proxy and the destination end of proxy interaction. If Proxy represents the client, then BBinder represents the server. BpBinder and BBinder are one-to-one, that is, a BpBinder can only interact with the corresponding BBinder. The above code creates the BpBinder in the defaultServiceManager() function, passing the value of handle to the BpBinder constructor. This zero has important implications for Binder systems as a whole – because it represents the BBinder that ServiceManager corresponds to.

  • 2.2.3 interface_cast
frameworks/native/include/binder/IInterface.h

/ / 41
template<typename INTERFACE>
inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
{
    return INTERFACE::asInterface(obj);
}
// This is a template function, equivalent to
inline sp<IServiceManager>interface_cast(const sp<IBinder>& obj)
{
    return IServiceManager::asInterface(obj);
}
Copy the code

2.2.3.1 IInterface. H

frameworks/native/include/binder/IInterface.h

/ / 74
#define DECLARE_META_INTERFACE(INTERFACE)                               \
    static const android::String16 descriptor;                          \
    static android::sp<I##INTERFACE> asInterface(                       \
            const android::sp<android::IBinder>& obj);                  \
    virtual const android::String16& getInterfaceDescriptor() const;    \
    I##INTERFACE();                                                     \
    virtual ~I##INTERFACE();                                            \


#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME)                       \
    const android::String16 I##INTERFACE::descriptor(NAME);             \
    const android::String16&                                            \
            I##INTERFACE::getInterfaceDescriptor() const {              \
        return I##INTERFACE::descriptor;                                \
    }                                                                   \
    android::sp<I##INTERFACE> I##INTERFACE::asInterface(                \
            const android::sp<android::IBinder>& obj)                   \
    {                                                                   \
        android::sp<I##INTERFACE> intr;                                 \
        if(obj ! = NULL) { \ intr = static_cast<I##INTERFACE*>(                          \
                obj->queryLocalInterface(                               \
                        I##INTERFACE::descriptor).get());               \
            if (intr == NULL) {                                         \
                intr = new Bp##INTERFACE(obj);                          \
            }                                                           \
        }                                                               \
        return intr;                                                    \
    }                                                                   \
    I##INTERFACE::I##INTERFACE() { }                                    \
    I##INTERFACE::~I##INTERFACE() { }                                   \
Copy the code

There are two key macro definitions

2.2.3.2 IServiceManager: : asInterface

frameworks/native/include/binder/IServiceManager.h

/ / 33
class IServiceManager : public IInterface
{
public:
    DECLARE_META_INTERFACE(ServiceManager);
    virtual sp<IBinder>         getService( const String16& name) const = 0;
    virtual sp<IBinder>         checkService( const String16& name) const = 0;
    virtual status_t            addService( const String16& name,
                                            const sp<IBinder>& service,
                                            bool allowIsolated = false) = 0;

    virtual Vector<String16>    listServices(a) = 0;

    enum {
        GET_SERVICE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
        CHECK_SERVICE_TRANSACTION,
        ADD_SERVICE_TRANSACTION,
        LIST_SERVICES_TRANSACTION,
    };
};
Copy the code

Available by macro definition expansion in iinterface.h

static const android::String16 descriptor;
static android::sp< IServiceManager > asInterface(const 
android::sp<android::IBinder>& obj)
virtual const android::String16& getInterfaceDescriptor(a) const;
IServiceManager(a);virtual ~IServiceManager(a);Copy the code

The process is basically declaring the asInterface(),getInterfaceDescriptor() methods.

frameworks/native/libs/binder/IServiceManager.cpp

/ / 185
IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager");
Copy the code

Available by macro definition expansion in iinterface.h

const android::String16 
IServiceManager::descriptor(" android. OS. IServiceManager ");
const android::String16& IServiceManager::getInterfaceDescriptor(a) const
{
     return IServiceManager::descriptor;
}
 android::sp<IServiceManager> IServiceManager::asInterface(const 
android::sp<android::IBinder>& obj)
{
       android::sp<IServiceManager> intr;
        if(obj ! =NULL) {
           intr = static_cast<IServiceManager *>(
               obj->queryLocalInterface(IServiceManager::descriptor).get());
           if (intr == NULL) {
                // New BpServiceManager(BpBinder)
                intr = new BpServiceManager(obj); }}return intr;
}
IServiceManager::IServiceManager () { }
IServiceManager::~ IServiceManager() {}Copy the code

2.2.4 BpServiceManager

frameworks/native/libs/binder/IServiceManager.cpp

/ / 126
class BpServiceManager : public BpInterface<IServiceManager>
{
public:
    BpServiceManager(const sp<IBinder>& impl)
        : BpInterface<IServiceManager>(impl)
    {
    }
...

};
Copy the code

2.2.4.1 BpInterface: : BpInterface

frameworks/native/include/binder/IInterface.h

/ / 134
template<typename INTERFACE>
inline BpInterface<INTERFACE>::BpInterface(const sp<IBinder>& remote)
    : BpRefBase(remote)
Copy the code

2.2.4.1.1 BpRefBase

frameworks/native/libs/binder/Binder.cpp

// 241 mRemote points to New BpBinder(0) so that BpServiceManager can communicate with Binder
BpRefBase::BpRefBase(const sp<IBinder>& o)
    : mRemote(o.get()), mRefs(NULL), mState(0)
Copy the code

So, the sequence diagram for getting the ServiceManager should look like this