Binder Analysis – Overall overview

Binder mechanism is familiar to you. This blog will explain the code process of AMS registration, and it will be a long one. Please be patient.

(The following analysis is Android 6.0 source code)

How does the ServiceManager start?

AMS is registered with a ServiceManager (hereafter referred to as SM) upon startup

So how does SM get started?

SM is created by the init process by parsing the init.rc file. The corresponding executable program servicemanager is created by the source file service_manager.c and the process name is Servicemanager

The entry function to start SM is the main function in service_manager.c

int main(int argc, char **argv)
{
    struct binder_state *bs;
    // Open binder driver to map 128K memory space
    bs = binder_open(128*1024); .// Register the current process as SM
    if (binder_become_context_manager(bs))
    {
        ALOGE("cannot become context manager (%s)\n", strerror(errno));
        return - 1; }...// Enter an infinite loop to listen for requests from AMS
    binder_loop(bs, svcmgr_handler);
    return 0;
}
Copy the code

binder_open()

// frameworks/native/cmds/servicemanager/binder.c
struct binder_state *binder_open(size_t mapsize)
{
    struct binder_state *bs;
    struct binder_version vers;.// Open the binder driver, get the file descriptor, and call binder_open in the binder driver
    bs->fd = open("/dev/binder", O_RDWR); .// Map memory size: 128K
    bs->mapsize = mapsize;
    // Call binder_mmap in binder drivers
    // Map 128K memory space between user space and kernel space of the current process
    bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0); .returnbs; . }Copy the code

It is important to note that the size of SM’s cross-process communication data cannot exceed 128K

Since SM records only references to entity nodes in binder drivers for registered services (which will be covered later), 128K is sufficient

binder_become_context_manager()

// frameworks/native/cmds/servicemanager/binder.c
int binder_become_context_manager(struct binder_state *bs)
{
    // The binder_ioctl function in binder drivers is called by the system with the instruction BINDER_SET_CONTEXT_MGR
    return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
}
Copy the code

binder_ioctl()

// kernel/drivers/staging/android/binder.c
static long binder_ioctl(struct file *filp, 
                        unsigned int cmd, // CMD is the BINDER_WRITE_READ we pass in
                        unsigned long arg // arg is the BWR we passed in
){
    // Obtain device nodes driven by binder
    struct binder_proc *proc = filp->private_data;
    struct binder_thread *thread;.// Get the binder thread
    // If the pid has not created a binder thread, create a binder thread and return.
    // thread->looper = BINDER_LOOPER_STATE_NEED_RETURN
    // thread->return_error = BR_OK
    // thread->return_error2 = BR_OK
    thread = binder_get_thread(proc); .switch (cmd)
    {
        ......
        case BINDER_SET_CONTEXT_MGR:
            ret = binder_ioctl_set_ctx_mgr(filp); .break; . }...return ret;
}
Copy the code

binder_ioctl_set_ctx_mgr()

// kernel/drivers/staging/android/binder.c
static int binder_ioctl_set_ctx_mgr(struct file *filp)
{
    // Obtain device node entities for binder drivers by using filp->private_data
    struct binder_proc *proc =filp->private_data; .// Ensure that binder_context_mgr_node is created only once
    if (context->binder_context_mgr_node)
    {
        ......
        gotoout; }...// whether the uid is valid, currently not
    if (uid_valid(context->binder_context_mgr_uid))
    {
        if (!uid_eq(context->binder_context_mgr_uid, curr_euid))
        {
            ......
            gotoout; }}else
    {
        // Set the current thread euID as the UID of the SM
        context->binder_context_mgr_uid = curr_euid;
    }
    // Create SM's binder node entities in binder drivers
    context->binder_context_mgr_node = binder_new_node(proc, 0.0); . out:return ret;
}
Copy the code
binder_new_node()
// kernel/drivers/staging/android/binder.c
static struct binder_node *binder_new_node(
            struct binder_proc *proc, // Device node entities driven by binder
            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;.// Allocate kernel space to the newly created binder_node
    node = kzalloc(sizeof(*node), GFP_KERNEL); .// Add the newly created binder_node to the binder_node red-black tree of the device node
    rb_link_node(&node->rb_node, parent, p);
    rb_insert_color(&node->rb_node, &proc->nodes); .// Initialize the newly created binder_node
    node->proc = proc;
    node->ptr = ptr;
    node->cookie = cookie;
    node->work.type = BINDER_WORK_NODE;
    // Initialize toDO and wait queues
    INIT_LIST_HEAD(&node->work.entry);
    INIT_LIST_HEAD(&node->async_todo); .return node;
}
Copy the code

inbinder_become_context_managerThe main function is to create SM node entities in binder drivers

binder_loop()

// frameworks/native/cmds/servicemanager/binder.c
void binder_loop(struct binder_state *bs, binder_handler func)
{
    int res;
    struct binder_write_read bwr;
    uint32_t readbuf[32];

    bwr.write_size = 0;
    bwr.write_consumed = 0;
    bwr.write_buffer = 0;

    readbuf[0] = BC_ENTER_LOOPER;
    // Send BC_ENTER_LOOPER to binder drivers
    binder_write(bs, readbuf, sizeof(uint32_t)); . }Copy the code

binder_write()

// frameworks/native/cmds/servicemanager/binder.c
int binder_write(struct binder_state *bs, 
                 void *data, // Start address of readbuf
                 size_t len // Readbuf length
){
    struct binder_write_read bwr;
    int res;
    bwr.write_size = len;
    bwr.write_consumed = 0;
    bwr.write_buffer = (uintptr_t) data;
    bwr.read_size = 0;
    bwr.read_consumed = 0;
    bwr.read_buffer = 0;
    Binder_ioctl is called by the binder driver with BINDER_WRITE_READ
    res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
    if (res < 0) {
        fprintf(stderr,"binder_write: ioctl failed (%s)\n".strerror(errno));
    }
    return res;
}
Copy the code

binder_ioctl()

// kernel/drivers/staging/android/binder.c
static long binder_ioctl(struct file *filp, 
                        unsigned int cmd, // CMD is the BINDER_WRITE_READ we pass in
                        unsigned long arg // arg is the BWR we passed in
){
    // Obtain device nodes driven by binder
    struct binder_proc *proc = filp->private_data;
    struct binder_thread *thread;.// Get the binder thread
    // If the pid has already created a binder thread, return the corresponding binder thread.
    // thread->looper = BINDER_LOOPER_STATE_NEED_RETURN
    // thread->return_error = BR_OK
    // thread->return_error2 = BR_OK
    thread = binder_get_thread(proc); .switch (cmd)
    {
        case BINDER_WRITE_READ:
            ret = binder_ioctl_write_read(filp, cmd, arg, thread); .break; . }...return ret;
}
Copy the code
binder_get_thread()
static struct binder_thread *binder_get_thread(struct binder_proc *proc)
{
    struct binder_thread *thread = NULL;
    struct rb_node *parent = NULL;
    // Binder thread pool root pointer
    struct rb_node **p = &proc->threads.rb_node;
    
    // Walk through the binder thread pool to find a binder thread that matches the current thread (with the same PID)
    while (*p)
    {
        parent = *p;
        Rb_node -> binder_thread
        thread = rb_entry(parent, struct binder_thread, rb_node);
        
        if (current->pid < thread->pid)
            p = &(*p)->rb_left;
        else if (current->pid > thread->pid)
            p = &(*p)->rb_right;
        else
            // If it is found, break the loop and stop iterating
            break;
    }
    
    // If there are no records in the binder thread pool, a new binder thread is created
    if (*p == NULL)
    {
        thread = kzalloc(sizeof(*thread), GFP_KERNEL);
        if (thread == NULL)
            return NULL;
        binder_stats_created(BINDER_STAT_THREAD);
        // Record the process that binder threads belong to
        thread->proc = proc;
        // Record the PID of binder threads
        thread->pid = current->pid;
        // Initializes the WAIT queue for binder threads
        init_waitqueue_head(&thread->wait);
        // Initializes the TOdo queue for binder threads
        INIT_LIST_HEAD(&thread->todo);
        // Put binder threads into binder thread pools
        rb_link_node(&thread->rb_node, parent, p);
        rb_insert_color(&thread->rb_node, &proc->threads);
        thread->looper |= BINDER_LOOPER_STATE_NEED_RETURN;
        thread->return_error = BR_OK;
        thread->return_error2 = BR_OK;
    }
    return thread;
}
Copy the code

A binder thread pool is essentially a red-black tree data structure that binder threads are converted to rB_node type for storage

binder_ioctl_write_read()
// kernel/drivers/staging/android/binder.c
static int binder_ioctl_write_read(struct file *filp,
				unsigned int cmd, unsigned long arg,
				struct binder_thread *thread
){
    struct binder_proc *proc =filp->private_data; .void __user *ubuf = (void __user *)arg;
    struct binder_write_read bwr;
    
    // Copy the binder_write_read structure (ubuF) describing the data from user space to kernel space (BWR)
    if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
    ......
    // bwr.write_size > 0, if hit
    if (bwr.write_size > 0)
    {
        // Send instructions to binder drivers
        ret = binder_thread_write(proc, thread, bwr.write_buffer, bwr.write_size, &bwr.write_consumed); . }// bwr.read_size = 0, if not matched
    if (bwr.read_size > 0) {... }...return ret;
}
Copy the code
binder_thread_write()
// kernel/drivers/staging/android/binder.c
static int binder_thread_write(struct binder_proc *proc,
			struct binder_thread *thread,
			binder_uintptr_t binder_buffer, // Start address of readbuf
			size_t size, // Readbuf length
			binder_size_t *consumed
){
    uint32_t cmd;
    struct binder_context *context = proc->context;
    void __user *buffer = (void __user *)(uintptr_t)binder_buffer;
    // A pointer to the starting address of readbuf memory
    void __user *ptr = buffer + *consumed;
    // A pointer to the end address of readbuf memory
    void __user *end = buffer + size;
    
    // Iterate over the memory pointer of readbuf to fetch the instruction
    while (ptr < end && thread->return_error == BR_OK)
    {
        // Read instructions from readbuf, BC_ENTER_LOOPER
        if (get_user(cmd, (uint32_t __user *)ptr))
            return -EFAULT;
        // Move the pointer back
        ptr += sizeof(uint32_t);
        switch (cmd)
        {
            ......
            case BC_ENTER_LOOPER:
                ......
                // Add BINDER_LOOPER_STATE_ENTERED to the looper flag bit for binder threads
                thread->looper |= BINDER_LOOPER_STATE_ENTERED;
                break; . }... }return 0;
}
Copy the code

When the binder_thread_write function is finished, it returns to the binder_loop function and continues in an infinite loop

// frameworks/native/cmds/servicemanager/binder.c
void binder_loop(struct binder_state *bs, binder_handler func)
{
    int res;
    struct binder_write_read bwr;
    uint32_t readbuf[32];

    bwr.write_size = 0;
    bwr.write_consumed = 0;
    bwr.write_buffer = 0; .for (;;)
    {
        bwr.read_size = sizeof(readbuf);
        bwr.read_consumed = 0;
        bwr.read_buffer = (uintptr_t) readbuf;
        Binder_ioctl is called by the binder driver with BINDER_WRITE_READ
        res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr); . }}Copy the code

binder_ioctl()

// kernel/drivers/staging/android/binder.c
static long binder_ioctl(struct file *filp, 
                        unsigned int cmd, // CMD is the BINDER_WRITE_READ we pass in
                        unsigned long arg // arg is the BWR we passed in
){
    // Obtain device nodes driven by binder
    struct binder_proc *proc = filp->private_data;
    struct binder_thread *thread;.// Get the binder thread
    // If the pid has already created a binder thread, return the corresponding binder thread.
    // thread->looper = BINDER_LOOPER_STATE_NEED_RETURN + BINDER_LOOPER_STATE_ENTERED
    // thread->return_error = BR_OK
    // thread->return_error2 = BR_OK
    thread = binder_get_thread(proc); .switch (cmd)
    {
        case BINDER_WRITE_READ:
            ret = binder_ioctl_write_read(filp, cmd, arg, thread); .break; . }...return ret;
}
Copy the code

binder_ioctl_write_read()

// kernel/drivers/staging/android/binder.c
static int binder_ioctl_write_read(struct file *filp,
				unsigned int cmd, unsigned long arg,
				struct binder_thread *thread
){
    struct binder_proc *proc =filp->private_data; .void __user *ubuf = (void __user *)arg;
    struct binder_write_read bwr;
    
    // Copy the binder_write_read structure (ubuF) describing the data from user space to kernel space (BWR)
    if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
    ......
    // bwr.write_size = 0, if not matched
    if (bwr.write_size > 0) {... }// bwr.read_size > 0, if hit
    if (bwr.read_size > 0)
    {
        // Read the instructions returned by binder drivers
        ret = binder_thread_read(proc, thread, bwr.read_buffer, bwr.read_size, &bwr.read_consumed, filp->f_flags & O_NONBLOCK); . }...return ret;
}
Copy the code
binder_thread_read()
static int binder_thread_read(struct binder_proc *proc,
			      struct binder_thread *thread,
			      binder_uintptr_t binder_buffer, size_t size,
			      binder_size_t *consumed, int non_block
){
    void __user *buffer = (void __user *)(uintptr_t)binder_buffer;
    // A pointer to the starting address of readbuf memory
    void __user *ptr = buffer + *consumed;
    // A pointer to the end address of readbuf memory
    void __user *end = buffer + size;
    
    int ret = 0;
    int wait_for_proc_work;

    // Now consumed = 0, if matches
    if (*consumed == 0)
    {
        // Add the directive BR_NOOP to readbuf
        if (put_user(BR_NOOP, (uint32_t __user *)ptr))
            return -EFAULT;
        // Move the pointer back
        ptr += sizeof(uint32_t);
    }

    Thread ->todo = NULL, thread->transaction_stack = NULL,
    // wait_for_proc_work = true
    wait_for_proc_work = thread->transaction_stack == NULL && list_empty(&thread->todo); . thread->looper |= BINDER_LOOPER_STATE_WAITING;if (wait_for_proc_work)
        // The number of binder threads available to the current process +1proc->ready_threads++; .if (wait_for_proc_work)
    {
        ......
        // Filp ->f_flags & O_NONBLOCK is already assigned
        // non_block > 0, else
        if (non_block)
        {
            ......
        }
        else
            Thread ->todo = NULL, binder_has_proc_work returns false,
            // Suspend the binder thread
            ret = wait_event_freezable_exclusive(proc->wait, 
                                                 binder_has_proc_work(proc, thread));
    }
    else{... }... }Copy the code

At this point, the SM thread is suspended, waiting for another process to communicate with it and wake it up

The awakened SM thread continues to execute the unfinished binder_thread_read function here

The structure of readBUf is as follows

How do I register for AMS?

The process of registering AMS into SM is also the process of COMMUNICATION between AMS and SM

Registration for AMS is performed in SystemServer#main

// frameworks/base/services/java/com/android/server/SystemServer.java
public static void main(String[] args)
{
    new SystemServer().run();
}

private void run(a)
{.../ / create SystemServiceManager
    mSystemServiceManager = newSystemServiceManager(mSystemContext); . startBootstrapServices(); }private void startBootstrapServices(a)
{.../ / create ActivityManagerService through reflection. Lifecycle and get the AMS objectmActivityManagerService = mSystemServiceManager.startService( ActivityManagerService.Lifecycle.class).getService(); .// Start the system process for AMS
    mActivityManagerService.setSystemProcess();
}

// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
public void setSystemProcess(a)
{...// Register AMS with SM
    ServiceManager.addService(Context.ACTIVITY_SERVICE, this.true); . }// frameworks/base/core/java/android/os/ServiceManager.java
public static void addService(String name, IBinder service, boolean allowIsolated)
{... getIServiceManager().addService(name, service, allowIsolated); . }Copy the code

ServiceManager.getIServiceManager()

// frameworks/base/core/java/android/os/ServiceManager.java
private static IServiceManager getIServiceManager(a)
{
    if(sServiceManager ! =null)
    {
        return sServiceManager;
    }
    / / return ServiceManagerProxy
    sServiceManager = 
        	ServiceManagerNative.asInterface(BinderInternal.getContextObject());
    return sServiceManager;
}
Copy the code

BinderInternal.getContextObject()

// frameworks/base/core/java/com/android/internal/os/BinderInternal.java
public static final native IBinder getContextObject(a);

// frameworks/base/core/jni/android_util_Binder.cpp
static const JNINativeMethod gBinderInternalMethods[] = {
    ......
    { "getContextObject"."()Landroid/os/IBinder;", 
			(void*)android_os_BinderInternal_getContextObject },
    ......
};

static jobject android_os_BinderInternal_getContextObject(JNIEnv* env, jobject clazz)
{
    // ProcessState::self() --> Open binder driver and create ProcessState (ProcessState is singleton)
    / / ProcessState: : getContextObject (NULL) - > create BpBinder object and return
    sp<IBinder> b = ProcessState::self()->getContextObject(NULL);
    // Create a BinderProxy object and return it
    return javaObjectForIBinder(env, b);
}
Copy the code

ProcessState::self()

// frameworks/native/libs/binder/ProcessState.cpp
sp<ProcessState> ProcessState::self(a)
{
    Mutex::Autolock _l(gProcessMutex);
    // Singleton mode
    if(gProcess ! =NULL)
    {
        return gProcess;
    }
    / / create ProcessState
    gProcess = new ProcessState;
    return gProcess;
}

// BINDER_VM_SIZE the BINDER_VM_SIZE ranges from 1M to 8K
#define BINDER_VM_SIZE ((1*1024*1024) - (4096 *2))

ProcessState::ProcessState()
    : mDriverFD(open_driver()) // Start the binder driver. {// If the binder driver is enabled successfully, the binder driver node is obtained
    if (mDriverFD >= 0)
    {
        // Call binder_mmap in binder drivers
        // Map BINDER_VM_SIZE (1m-8K) between user space and kernel space of the current process
        mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0); . }... }Copy the code

The size of AMS cross-process communication data cannot exceed 1m-8K

This is a common interview question: Does an Intent have a size limit on the data it transmits? What is the size limit?

The answer is 1M minus 8K

Intents are a means of communication between the four major components, and AMS manages the four components. Therefore, communication with AMS is required with intEnts. Due to limitations of binder mechanisms, the data size of communication with AMS cannot exceed 1M to 8K

ProcessState::getContextObject()

// frameworks/native/libs/binder/ProcessState.cpp
sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
{
    return getStrongProxyForHandle(0);
}

sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{ sp<IBinder> result; .// The current handle is 0, and if matches
    if (handle == 0)
    {
        Parcel data;
        // Test SM readiness through the ping operation
        status_t status = IPCThreadState::self() - >transact(0, IBinder::PING_TRANSACTION, 
                                                           data, NULL.0);
        if (status == DEAD_OBJECT)
            return NULL;
    }
    // Create a BpBinder object with handle 0
    b = new BpBinder(handle); . result = b; .return result;
}
Copy the code

javaObjectForIBinder()

// frameworks/base/core/jni/android_util_Binder.cpp
jobject javaObjectForIBinder(JNIEnv* env, 
                            const sp<IBinder>& val // val = BpBinder
){...// Find the BinderProxy object from gBinderProxyOffsets
    // Object is null because BinderProxy has not been created
    jobject object = (jobject)val->findObject(&gBinderProxyOffsets);
    if(object ! =NULL)
    {
        // Return the BinderProxy object by looking up the reference chain of the BinderProxy object to determine whether it is being referenced
        jobject res = jniGetReferent(env, object);
        // If BinderProxy object is being referenced
        if(res ! =NULL)
        {
            ALOGV("objectForBinder %p: found existing %p! \n", val.get(), res);
            // Return the reference object
            returnres; }...// Remove all references to the current BinderProxy object
        android_atomic_dec(&gNumProxyRefs);
        val->detachObject(&gBinderProxyOffsets);
        env->DeleteGlobalRef(object);
    }
    
    Create a new BinderProxy object
    object = env->NewObject(gBinderProxyOffsets.mClass, 
                            gBinderProxyOffsets.mConstructor);
    if(object ! =NULL)
    {
        // Assign mObject (BpBinder) to gBinderProxyOffsets,
        // Record the BpBinder object
        env->SetLongField(object, gBinderProxyOffsets.mObject, (jlong)val.get());
        
        // Create a smart pointer to BpBinder
        val->incStrong((void*)javaObjectForIBinder);
        
        The JNI environment variable (env) generates a weak reference to the BinderProxy object for retrieval
        jobject refObject = env->NewGlobalRef(
                env->GetObjectField(object, gBinderProxyOffsets.mSelf));
        
        // Add BinderProxy object information to BpBinder's member variable mObjects,
        // Bind BinderProxy to BpBinder
        val->attachObject(&gBinderProxyOffsets, refObject, 
                          jnienv_to_javavm(env), proxy_cleanup); .// Binderproxy. mOrgue member variable records the death notification object
        env->SetLongField(object, gBinderProxyOffsets.mOrgue, 
                          reinterpret_cast<jlong>(drl.get())); .// The BinderProxy object reference count is incremented by one to indicate that the BinderProxy object has been referenced
        android_atomic_inc(&gNumProxyRefs); . }return object;
}
Copy the code

Each BinderProxy object is bound to a BpBinder object, a BinderProxy object is regenerated and a BpBinder object is rebound each time javaObjectForIBinder() is called

The BpBinder object bound to BinderProxy corresponds to SM (handle is 0).

BinderInternal.getContextObject()The function returns a BinderProxy object with a BpBinder object bound to the Native layer (corresponding to SM).

ServiceManagerNative.asInterface()

// frameworks/base/core/java/android/os/ServiceManagerNative.java
static public IServiceManager asInterface( IBinder obj // obj = BinderProxy ){
    if (obj == null)
    {
        return null;
    }
    IServiceManager in = (IServiceManager)obj.queryLocalInterface(descriptor);
    if(in ! =null)
    {
        return in;
    }
    return new ServiceManagerProxy(obj);
}

// frameworks/base/core/java/android/os/BinderProxy.java
public IInterface queryLocalInterface(String descriptor)
{
    return null;
}
Copy the code

getIServiceManager()The ServiceManagerProxy function returns a ServiceManagerProxy object that holds a BinderProxy object

ServiceManagerProxy.addService()

// frameworks/base/core/java/android/os/ServiceManagerNative$ServiceManagerProxy.java
public void addService(String name, IBinder service, boolean allowIsolated)
{
    / / create the data
    Parcel data = Parcel.obtain();
    / / create the reply
    Parcel reply = Parcel.obtain();
    data.writeInterfaceToken(IServiceManager.descriptor);
    // Write the AMS name to data
    data.writeString(name);
    // write AMS to data
    data.writeStrongBinder(service);
    data.writeInt(allowIsolated ? 1 : 0);
    // mRemote = BinderProxy, equivalent to calling binderproxy.transact
    mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply, 0);
    reply.recycle();
    data.recycle();
}
Copy the code

How does AMS package itself?

// frameworks/base/core/java/android/os/ServiceManagerNative$ServiceManagerProxy.java
public void addService(String name, IBinder service, boolean allowIsolated)
{
    / / create the dataParcel data = Parcel.obtain(); .// write AMS to datadata.writeStrongBinder(service); . }Copy the code

Parcel.writeStrongBinder()

// frameworks/base/core/java/android/os/Parcel.java
public final void writeStrongBinder(IBinder val)
{
    nativeWriteStrongBinder(mNativePtr, val);
}

// frameworks/base/core/jni/android_os_Parcel.cpp
static const JNINativeMethod gParcelMethods[] = {
    ......
    {"nativeWriteStrongBinder"."(JLandroid/os/IBinder;) V", (void*)android_os_Parcel_writeStrongBinder},
    ......
}

static void android_os_Parcel_writeStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr, jobject object // object = AMS ){
    // Cast Java layer Parcel type to Native layer Parcel type.
    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
    if(parcel ! = NULL) {conststatus_t err = parcel->writeStrongBinder(ibinderForJavaObject(env, object)); . }}Copy the code

ibinderForJavaObject()

// frameworks/base/core/jni/android_util_Binder.cpp
sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj // object = AMS ){
    if (obj == NULL)
        return NULL;
    // if obj is type Binder, then obj = AMS, AMS inherits from binder.java, if hit
    if (env->IsInstanceOf(obj, gBinderOffsets.mClass))
    {
        // Get the JavaBBinderHolder object from the gBinderOffsets. MObject member property
        JavaBBinderHolder* jbh = (JavaBBinderHolder*) env->GetLongField(obj, gBinderOffsets.mObject);
        // create JavaBBinder with JavaBBinderHolder#get
        returnjbh ! = NULL ? jbh->get(env, obj) : NULL; }...return NULL;
}
Copy the code

The JavaBBinderHolder is created with AMS creation and is stored in gBinderOffsets. MObject

JavaBBinder objects can be created by calling the JavaBBinderHolder#get function

The JavaBBinder object created at this point holds AMS in the mObject field

ibinderForJavaObjectThe function returns a JavaBBinder object that holds AMS

Parcel::writeStrongBinder()

// frameworks/native/libs/binder/Parcel.cpp
status_t Parcel::writeStrongBinder(const sp<IBinder>& val)
{
    return flatten_binder(ProcessState::self(), val, this);
}

status_t flatten_binder(const sp<ProcessState>& /*proc*/.const sp<IBinder>& binder, // binder = JavaBBinder
    Parcel* out / / out = ServiceManagerProxy. AddSevice function defined in the data
){
    // Encapsulates JavaBBinderflat_binder_object obj; .if(binder ! =NULL)
    {
        // Check whether binder object is BpBinder or BBinder
        // JavaBBinder is BBinder, local is not NULL, else
        IBinder *local = binder->localBinder(a);if(! local) { ...... }else
        {
            obj.type = BINDER_TYPE_BINDER;
            // local->getWeakRefs() = JavaBBinder = AMS
            obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs());
            obj.cookie = reinterpret_cast<uintptr_t>(local); }}else{... }return finish_flatten_binder(binder, obj, out);
}

inline static status_t finish_flatten_binder(
            const sp<IBinder>& binder, // binder = JavaBBinder
            const flat_binder_object& flat, 
            Parcel* out / / out = ServiceManagerProxy. AddSevice function defined in the data
){
    // Write the flat_binder_object object to data
    return out->writeObject(flat, false);
}
Copy the code

Flat_binder_object will appear later in the process and should be remembered; When the data is transferred to the binder driver, it is converted to a flat_binder_object structure for processing

Flat_binder_object encapsulates JavaBBinder, which in turn holds AMS. Flat_binder_object encapsulates AMS

Note that flat_binder_object.type = BINDER_TYPE_BINDER

AMS is eventually encapsulated as flat_binder_object and written to data

How does AMS send itself to SM?

// frameworks/base/core/java/android/os/ServiceManagerNative$ServiceManagerProxy.java
public void addService(String name, IBinder service, boolean allowIsolated)
{
    / / create the dataParcel data = Parcel.obtain(); .// mRemote = BinderProxy, equivalent to calling binderproxy.transact
    mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply, 0); . }Copy the code

BinderProxy.transact()

// android\frameworks\base\core\java\android\os\Binder.java
public boolean transact(int code, Parcel data, Parcel reply, int flags)
{...return transactNative(code, data, reply, flags);
}

public native boolean transactNative(int code, Parcel data, Parcel reply, int flags);
            
// android\frameworks\base\core\jni\android_util_Binder.cpp
static const JNINativeMethod gBinderProxyMethods[] = {
    ......
    {"transactNative"."(ILandroid/os/Parcel; Landroid/os/Parcel; I)Z", 
            (void*)android_os_BinderProxy_transact},
    ......
};

// android\frameworks\base\core\jni\android_util_Binder.cpp
static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj, jint code, // code = ADD_SERVICE_TRANSACTION jobject dataObj, jobject replyObj, jint flags ){...// Convert the type of dataObj to ParcelParcel* data = parcelForJavaObject(env, dataObj); .// Convert the type of replyObj to ParcelParcel* reply = parcelForJavaObject(env, replyObj); ./ / get gBinderProxyOffsets mObject BpBinder objects stored inIBinder* target = (IBinder*) env->GetLongField(obj, gBinderProxyOffsets.mObject); .// Call the transact function to the BpBinder objectstatus_t err = target->transact(code, *data, reply, flags); . }// android\frameworks\native\libs\binder\BpBinder.cpp
status_t BpBinder::transact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    ......
    // mHandle = 0status_t status = IPCThreadState::self()->transact(mHandle, code, data, reply, flags); . }Copy the code

IPCThreadState::self()

// android\frameworks\native\libs\binder\IPCThreadState.cpp

static pthread_mutex_t gTLSMutex = PTHREAD_MUTEX_INITIALIZER; // Concurrent lock object
static bool gHaveTLS = false; // Indicates whether TLS has been created
static pthread_key_t gTLS = 0; // The key stored in TLS

IPCThreadState* IPCThreadState::self(a)
{
    if (gHaveTLS)
    {
restart:
        const pthread_key_t k = gTLS;
        // Call pthread_getSpecific to retrieve stored data via gTLS
        IPCThreadState* st = (IPCThreadState*)pthread_getspecific(k);
        if (st) return st;
        return newIPCThreadState; }...pthread_mutex_lock(&gTLSMutex); // Lock to prevent concurrent access by thread
    // gHaveTLS If the initial value is false, TLS is not created
    if(! gHaveTLS) {// Call pthread_key_create to create TLS and assign to gTLS
        // (pthread_key_create returns 0 on success, error code on failure)
        if (pthread_key_create(&gTLS, threadDestructor) ! =0)
        {
            pthread_mutex_unlock(&gTLSMutex); / / releases the lock
            return NULL; // create TLS error return null
        }
        gHaveTLS = true;
    }
    pthread_mutex_unlock(&gTLSMutex); / / releases the lock
    goto restart;
}

IPCThreadState::IPCThreadState()
    : mProcess(ProcessState::self()), // Call ProcessState::self. {// Call pthread_setSpecific to save the IPCThreadState object to TLS
    pthread_setspecific(gTLS, this); . mIn.setDataCapacity(256); // Set the mIn size
    mOut.setDataCapacity(256); // Set the size of mOut
}
Copy the code

The IPCThreadState::self() function completes the creation of the IPCThreadState object

In order to make the IPCThreadState object unique for each thread, the system uses TLS technology in Linux

TLS refers to Thread local storage (TLS). Each Thread has its own TLS and is a private space that is not shared by threads

You can get/set the contents of TLS space through the pthread_getSpecific/pthread_setSpecific functions

In the IPCThreadState::self() function, the IPCThreadState object is stored using TLS, making the IPCThreadState object unique to each thread

IPCThreadState::transact()

// android\frameworks\native\libs\binder\IPCThreadState.cpp
status_t IPCThreadState::transact(int32_t handle, // handle = 0
                        uint32_t code, // code = ADD_SERVICE_TRANSACTION
                        const Parcel& data,
                        Parcel* reply,
                        uint32_t flags
){
    // Data error check
    status_t err = data.errorCheck(a);// TF_ACCEPT_FDS = 0x10: allow the file descriptor to be included in the reply
    // TF_ONE_WAY: The current service is asynchronous and there is no need to wait
    // TF_ROOT_OBJECT: Contains the root object
    // TF_STATUS_CODE: contains a 32-bit status valueflags |= TF_ACCEPT_FDS; .// Write flat_binder_object (data) to mOut
    err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL); .// Check whether the current service is asynchronous.
    // AIDL is synchronous by default, unless the oneway keyword is used to define the AIDL interface.
    if ((flags & TF_ONE_WAY) == 0) {...// Reply is not empty
        if (reply)
        {
            // Wait for binder drivers to respond to events
            err = waitForResponse(reply);
        }
        else
        {
            Parcel fakeReply;
            // Wait for binder drivers to respond to events
            err = waitForResponse(&fakeReply); }... }else
    {
        // Do not wait for binder drivers to respond to events
        err = waitForResponse(NULL.NULL); }... }Copy the code

MOut is divided into two parts:

  • Command part (address high in mOut)

  • The data section, where the encapsulated FLAT_binder_object is located (address low in mOut)

The structure is shown in the figure below

IPCThreadState::waitForResponse()

// android\frameworks\native\libs\binder\IPCThreadState.cpp
status_t IPCThreadState::waitForResponse(
                    Parcel *reply,
                    status_t *acquireResult
){
    uint32_t cmd;
    int32_t err;
    // Loop to wait for results
    while (1)
    {
        // Call talkWithDriver to send instructions to binder drivers
        if ((err=talkWithDriver()) < NO_ERROR) break; .// Continue if there is no data in mIn
        if (mIn.dataAvail() = =0) continue; . }... }Copy the code
IPCThreadState::talkWithDriver()
// android\frameworks\native\libs\binder\IPCThreadState.cpp
status_t IPCThreadState::talkWithDriver(bool doReceive)
{...// mIn is the Parcel variable defined by the macro, and mIn is not assigned
    // min.dataposition () = min.datasize () = 0, needRead is true
    const bool needRead = mIn.dataPosition() >= mIn.dataSize(a); .const size_toutAvail = (! doReceive || needRead) ? mOut.dataSize() : 0;
    
    bwr.write_size = outAvail;
    // at this point, bwr.write_buffer points to the starting address of mOut
    bwr.write_buffer = (uintptr_t)mOut.data(a);// If you need to read data
    if (doReceive && needRead)
    {
        // dataCapacity = 256
        bwr.read_size = mIn.dataCapacity(a);// min.data () = 0
        bwr.read_buffer = (uintptr_t)mIn.data(a); }else // Set bwr.read_size to zero without reading data
         // Then binder_thread_read will not be executed in the binder_ioctl_write_read function
    {
        bwr.read_size = 0;
        bwr.read_buffer = 0; }... bwr.write_consumed =0;
    bwr.read_consumed = 0;
    // Loop instructions to binder drivers until they succeed
    do{...Binder_ioctl = binder_ioctl; // Binder_ioctl = binder_ioctl
        if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
            err = NO_ERROR;
        elseerr = -errno; . }while (err == -EINTR); // The while condition is true only if an ioctl error occurs,
                             // Therefore, if the message is sent successfully, it is executed only once.return err;
}
Copy the code
binder_ioctl()
// kernel/drivers/staging/android/binder.c
static long binder_ioctl(struct file *filp, 
                        unsigned int cmd, // CMD is the BINDER_WRITE_READ we pass in
                        unsigned long arg // arg is the BWR we passed in
){
    // Obtain device nodes driven by binder
    struct binder_proc *proc = filp->private_data;
    struct binder_thread *thread;.// Get the binder thread
    // If the pid has not created a binder thread, create a binder thread and return.
    // thread->looper = BINDER_LOOPER_STATE_NEED_RETURN
    // thread->return_error = BR_OK
    // thread->return_error2 = BR_OK
    thread = binder_get_thread(proc); .switch (cmd)
    {
        case BINDER_WRITE_READ:
            ret = binder_ioctl_write_read(filp, cmd, arg, thread); .break; . }...return ret;
}
Copy the code
binder_ioctl_write_read()
// kernel\drivers\staging\android\binder.c
static int binder_ioctl_write_read(struct file *filp,
				unsigned int cmd, unsigned long arg,
				struct binder_thread *thread)
{
    struct binder_proc *proc =filp->private_data; .void __user *ubuf = (void __user *)arg;
    struct binder_write_read bwr;

    // Copy the starting address of mOut from user space to kernel space (BWR)
    if (copy_from_user(&bwr, ubuf, sizeof(bwr)))
    {
        ret = -EFAULT;
        gotoout; }...// bwr.write_size > 0, if hit
    if (bwr.write_size > 0)
    {
        // Send instructions to binder drivers
        ret = binder_thread_write(proc, thread, bwr.write_buffer, bwr.write_size, &bwr.write_consumed); . }// bwr.read_size > 0, if hit
    if (bwr.read_size > 0)
    {
        // Read the instructions returned by binder drivers
        ret = binder_thread_read(proc, thread, bwr.read_buffer, bwr.read_size, &bwr.read_consumed, filp->f_flags & O_NONBLOCK); . }... out:return ret;
}
Copy the code
binder_thread_write()
// kernel\drivers\staging\android\binder.c
static int binder_thread_write(struct binder_proc *proc,
			struct binder_thread *thread,
			binder_uintptr_t binder_buffer, size_t size,
			binder_size_t *consumed)
{
    uint32_t cmd;
    struct binder_context *context = proc->context;
    void __user *buffer = (void __user *)(uintptr_t)binder_buffer;
    // A pointer to the starting address of mOut
    void __user *ptr = buffer + *consumed;
    // A pointer to the end address of mOut
    void __user *end = buffer + size;
    
    // Iterate over the mOut memory pointer to fetch the instruction
    while (ptr < end && thread->return_error == BR_OK)
    {
        // Copy the commands in the mOut command section from user space to kernel space (CMD),
        CMD = BC_TRANSACTION
        if (get_user(cmd, (uint32_t __user *)ptr))
            return -EFAULT;
        // Move the pointer back
        ptr += sizeof(uint32_t); .switch (cmd)
        {
            ......
            case BC_TRANSACTION:
            case BC_REPLY:
            {
                struct binder_transaction_data tr;
                // Copy binder_transaction_data in the mOut data section from user space to kernel space
                if (copy_from_user(&tr, ptr, sizeof(tr)))
                    return -EFAULT;
                // Move the pointer back
                ptr += sizeof(tr);
                // Call binder_transaction
                binder_transaction(proc, thread, &tr, cmd == BC_REPLY, 0);
                break; }... }... }... }Copy the code

It’s not really a copy yet

binder_transaction()
// kernel\drivers\staging\android\binder.c
static void binder_transaction(struct binder_proc *proc,
			       struct binder_thread *thread,
			       struct binder_transaction_data *tr, // mOut data section
				   int reply, // Reply = false
			       binder_size_t extra_buffers_size)
{...struct binder_transaction *t;
    struct binder_work *tcomplete;
    binder_size_t*offp, *off_end, *off_start; .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; .// Reply is false (CMD == BC_TRANSACTION)
    if (reply)
    {
        ......
    }
    else
    {
        // tr->target.handle = 0, else
        if (tr->target.handle)
        {
            ......
        }
        else
        {
            // Get the binder_node for SMtarget_node = context->binder_context_mgr_node; . }...// Get the binder_proc for SMtarget_proc = target_node->proc; . }// Get the TOdo queue and wait queue for SMtarget_list = &target_proc->todo; target_wait = &target_proc->wait; .// Generate a binder_transaction variable,
    // Describes the transaction to be done (target_thread->todo).
    // So that when the target object is woken up, it can fetch work from the queue.
    t = kzalloc(sizeof(*t), GFP_KERNEL); .// Generate a binder_work variable (tcomplete) to indicate that AMS has an unfinished job
    tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL); .// If hits
    if(! reply && ! (tr->flags & TF_ONE_WAY))// Non-oneway communication where the current thread is stored in the FROM field of the transaction
        t->from = thread;
    else
        t->from = NULL; .// Record the target process of this communicationt->to_proc = target_proc; .// Code = ADD_SERVICE_TRANSACTION
    t->code = tr->code;
    // Flags = 0t->flags = tr->flags; .// Allocate buffer from SM process
    // To complete this transaction, allocate memory from binder_mmap.
    t->buffer = binder_alloc_buf(target_proc, tr->data_size, tr->offsets_size, extra_buffers_size, ! reply && (t->flags & TF_ONE_WAY)); .// Record SM's binder_nodet->buffer->target_node = target_node; .// Record the starting address of the mOut data section
    off_start = (binder_size_t *)(t->buffer->data +
            ALIGN(tr->data_size, sizeof(void*))); offp = off_start; .// Copy mOut data from user space to kernel space (t->buffer->data)
    if (copy_from_user(t->buffer->data, (const void __user *)(uintptr_t)
                    tr->data.ptr.buffer, tr->data_size))
    ......
    // Record the end address of the mOut data section
    off_end = (void*)off_start + tr->offsets_size; .// Iterate over the memory pointer to the mOut data section
    for (; offp < off_end; offp++)
    {
        struct binder_object_header *hdr;.// Convert the data part of mOut to binder_object_headerhdr = (struct binder_object_header *)(t->buffer->data + *offp); .switch (hdr->type) HDR ->type = flat_binder_object.type = BINDER_TYPE_BINDER
        {
            case BINDER_TYPE_BINDER:
            case BINDER_TYPE_WEAK_BINDER:
            {
                struct flat_binder_object *fp;
                // Convert the data to a flat_binder_object structure
                fp = to_flat_binder_object(hdr);
                // Create an entity node for AMS in binder drivers and create a reference to that node (handle)
                ret = binder_translate_binder(fp, t, thread); . }break; . }}...CMD = BC_TRANSACTION, CMD! = BC_REPLY, reply = false
    if (reply)
    {
        ......
    }
    else if(! (t->flags & TF_ONE_WAY))// Operation is synchronous, hit{...// Record this transaction for future query
        // (SM uses this to know who called and returns data)
        thread->transaction_stack = t;
    }
    else{... }// Set t's type to BINDER_WORK_TRANSACTION
    t->work.type = BINDER_WORK_TRANSACTION;
    // Add t to the TOdo queue of SM process
    list_add_tail(&t->work.entry, target_list);
    // Set the binder_work type to BINDER_WORK_TRANSACTION_COMPLETE
    tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;
    // Add tComplete to the AMS thread todo queue
    list_add_tail(&tcomplete->entry, &thread->todo);
    // when SM is suspended, target_wait! = NULL, if hit
    if (target_wait)
        // Wake up SM process
        wake_up_interruptible(target_wait);
    return; . }Copy the code

The binder_transaction function does several things:

  1. Get the binder_proc structure for the SM process
  2. Generate a binder_transaction variable (for SM) and a binder_work variable (for AMS) to hold the information
  3. Copy the encapsulated FLAT_binder_object into shared memory created by binder_mmap (emphasis, one copy)
  4. Create AMS entity node in binder driver and create a reference to that node (Handle)
  5. Wake up the SM process by adding the binder_TRANSACTION variable to its TODO queue
  6. Add the binder_work variable to the TODO queue of the AMS calling thread, and AMS hangs and waits

The binder_transaction function really does IPC traffic

binder_thread_read()
// kernel\drivers\staging\android\binder.c
static int binder_thread_read(struct binder_proc *proc,
			      struct binder_thread *thread,
			      binder_uintptr_t binder_buffer, size_t size,
			      binder_size_t *consumed, int non_block)
{
    void __user *buffer = (void __user *)(uintptr_t)binder_buffer;
    // a pointer to the starting address of mIn memory
    void __user *ptr = buffer + *consumed;
    // Pointer to the end address of mIn memory
    void __user *end = buffer + size;

    int ret = 0;
    intwait_for_proc_work; . retry:Thread ->todo is not empty and wait_for_proc_work is false
    Thread ->todo is empty and wait_for_proc_work is true
    wait_for_proc_work = thread->transaction_stack == NULL && list_empty(&thread->todo);
    1. Execute else
    // 2. Run if
    if (wait_for_proc_work)
    {
        ......
        if (non_block) // Filp ->f_flags & O_NONBLOCK is already assigned
                       // non_block > 0, else{... }else
            Thread ->todo is null, binder_has_thread_work returns false, and AMS thread is suspended
            ret = wait_event_freezable_exclusive(proc->wait, binder_has_proc_work(proc, thread));
    }
    else
    {
        if (non_block) // Filp ->f_flags & O_NONBLOCK is already assigned
                       // non_block > 0, else{... }else
            Thread ->todo is not null. Binder_has_thread_work returns true. AMS threads will not be suspended
            ret = wait_event_freezable(thread->wait, binder_has_thread_work(thread)); }...// 1. The thread is not suspended and continues the while loop
    while (1)
    {
        uint32_t cmd;
        struct binder_transaction_data tr;
        struct binder_work *w;
        struct binder_transaction *t = NULL;
        
        If thread->todo is null, thread->todo is null. If thread->todo is null, thread->todo is null
        BINDER_WORK_TRANSACTION_COMPLETE binder_work_complete binder_work_complete
        // If thread->todo is null, execute else
        if (!list_empty(&thread->todo))
        {
            // 1. Fetch binder_work
            w = list_first_entry(&thread->todo, struct binder_work, entry);
        }
        else
        {
            // 2
            if (ptr - buffer == 4 && !(thread->looper & BINDER_LOOPER_STATE_NEED_RETURN))
                // 2. Run the code back to the retry position
                goto retry;
            break; }...W ->type is BINDER_WORK_TRANSACTION_COMPLETE
        switch (w->type)
        {
            ......
            case BINDER_WORK_TRANSACTION_COMPLETE:
            {
                // 1. Change the directive BR_TRANSACTION_COMPLETE
                cmd = BR_TRANSACTION_COMPLETE;
                // 1. Copy the command to mIn
                if (put_user(cmd, (uint32_t __user *)ptr))
                    return -EFAULT;
                // 1
                ptr += sizeof(uint32_t); .// 1. Delete the current binder_work from thread->todo
                list_del(&w->entry);
                // 1. Release binder_work memory
                kfree(w); . }break; . }// 1. T = null, if hit
        if(! t)continue; . } *consumed = ptr - buffer; .return 0;
}
Copy the code

The while loop in the binder_thread_read function executes twice, so the comments in the code indicate the ordinal number that corresponds to the number of times in the while loop

AMS is suspended at this point, waiting for the SM process to return data and wake up

When AMS is woken up, the binder_thread_read function resumes execution from there

What does the SM process do when it wakes up?

When the binder_transaction function completes, the SM thread wakes up and continues with the unfinished binder_thread_read function

binder_thread_read()

// kernel\drivers\staging\android\binder.c
static int binder_thread_read(struct binder_proc *proc,
			      struct binder_thread *thread,
			      binder_uintptr_t binder_buffer, size_t size,
			      binder_size_t *consumed, int non_block)
{...if (wait_for_proc_work)
        // Number of binder threads available to the current process -1proc->ready_threads--; thread->looper &= ~BINDER_LOOPER_STATE_WAITING; .while (1)
    {
        uint32_t cmd;
        struct binder_transaction_data tr;
        struct binder_work *w;
        struct binder_transaction *t = NULL; .// Add a binder_transaction to the binder_transaction function, proc->todo is not null
        else if (!list_empty(&proc->todo) && wait_for_proc_work)
        {
            // Fetch binder_transaction, but of type binder_work
            w = list_first_entry(&proc->todo, struct binder_work, entry); }...W ->type is BINDER_WORK_TRANSACTION
        switch (w->type)
        {
            ......
            case BINDER_WORK_TRANSACTION:
            {
                // Type conversion (binder_work -> binder_transaction)
                t = container_of(w, struct binder_transaction, work);
            } break; . }// t! = null, if not hit
        if(! t)continue; .T ->buffer->target_node = SM, not null, if hit
        if (t->buffer->target_node)
        {
            struct binder_node *target_node =t->buffer->target_node; tr.target.ptr = target_node->ptr; tr.cookie = target_node->cookie; .// The instruction is changed to BR_TRANSACTION
            cmd = BR_TRANSACTION;
        }
        else{... }// t->code = ADD_SERVICE_TRANSACTION
        tr.code = t->code;
        // t->flags = 0
        tr.flags = t->flags;
        
        // if t->from not NULL, if hit
        if (t->from)
        {
            struct task_struct *sender = t->from->proc->tsk;
            // Get the PID of AMS thread and record
            tr.sender_pid = task_tgid_nr_ns(sender, task_active_pid_ns(current));
        }
        else{... }// Record the memory address, size and other information of the mOut data part
        tr.data_size = t->buffer->data_size;
        tr.offsets_size = t->buffer->offsets_size;
        tr.data.ptr.buffer = (binder_uintptr_t) ((uintptr_t)t->buffer->data + 
                                                proc->user_buffer_offset);
        tr.data.ptr.offsets = tr.data.ptr.buffer + ALIGN(t->buffer->data_size, 
                                                         sizeof(void *));
        
        // copy the instruction BR_TRANSACTION into user space (readbuf in binder_loop)
        if (put_user(cmd, (uint32_t __user *)ptr))
            return -EFAULT;
        // Move the pointer back
        ptr += sizeof(uint32_t);
        
        // Copy information from the mOut data section to user space (readbuf in binder_loop)
        if (copy_to_user(ptr, &tr, sizeof(tr)))
            return -EFAULT;
        // Move the pointer back
        ptr += sizeof(tr); .// If hits
        if(cmd == BR_TRANSACTION && ! (t->flags & TF_ONE_WAY)) { t->to_parent = thread->transaction_stack; t->to_thread = thread;// Store t in the SM thread's transaction_stack
            thread->transaction_stack = t;
        }
        else{... }// Break the loop
        break; . } *consumed = ptr - buffer;Proc ->requested_threads = proc->ready_threads = 0
    // proc->requested_threads_started = 0 < proc->max_threads (default: 15),
    Thread ->looper = BINDER_LOOPER_STATE_NEED_RETURN + BINDER_LOOPER_STATE_ENTERED,
    // If the condition is met, if is hit
    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 number of binder threads that the current process needs to create +1
        proc->requested_threads++;
        // Copy the BR_SPAWN_LOOPER directive to user space (readbuf in binder_loop)
        if (put_user(BR_SPAWN_LOOPER, (uint32_t __user *)buffer))
            return-EFAULT; . }return 0;
}
Copy the code

When the binder_thread_read function completes, the binder_ioctl_write_read function completes, and returns to the binder_loop function to continue execution

The structure of readBUf is as follows

binder_loop()

// frameworks/native/cmds/servicemanager/binder.c
void binder_loop(struct binder_state *bs, binder_handler func)
{...for(;;) {... res =binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func); . }}Copy the code

binder_parse()

The rest of the instruction processing flow in readbuf can be ignored and the most important one is BR_TRANSACTION

// frameworks/native/cmds/servicemanager/binder.c
int binder_parse(struct binder_state *bs, 
                struct binder_io *bio,
                uintptr_t ptr, // PTR points to the starting address of readbuf in binder_loop
                size_t size, // size = length of readbuf in binder_loop
                binder_handler func
){
    int r = 1;
    // pointer to the bwr.read_buffer end address in binder_loop
    uintptr_t end = ptr + (uintptr_t) size;

    while (ptr < end)
    {
        // Uint32_t = uint32_t
        uint32_t cmd = *(uint32_t *) ptr;
        // Move the pointer back
        ptr += sizeof(uint32_t); .switch(cmd)
        {
            ......
            case BR_TRANSACTION:
            {
                // Convert the mOut data section to binder_transaction_data
                struct binder_transaction_data *txn =(struct binder_transaction_data *) ptr; .// func = service_manager.svcmgr_handler, if hit
                if (func)
                {
                    unsigned rdata[256/4];
                    struct binder_io msg;
                    struct binder_io reply;
                    int res;
                    // Initialize reply
                    bio_init(&reply, rdata, sizeof(rdata), 4);
                    // initialize the MSG to copy the information from the mOut data section to the MSG
                    bio_init_from_txn(&msg, txn);
                    // Execute the service_manager.svcmgr_handler function
                    res = func(bs, txn, &msg, &reply);
                    // Send reply to the binder driver
                    binder_send_reply(bs, &reply, txn->data.ptr.buffer, res);
                }
                // Move the pointer back
                ptr += sizeof(*txn);
                break; }... }}return r;
}
Copy the code

Func is a function pointer to the service_manager.svcmgr_handler function, so res = func(bs, TXN, & MSG, &reply); This line calls the service_manager.svcmgr_handler function

service_manager.svcmgr_handler()

// frameworks/native/cmds/servicemanager/service_manager.c
int svcmgr_handler(struct binder_state *bs,
                   struct binder_transaction_data *txn, // mOut data section
                   struct binder_io *msg, // mOut data section information
                   struct binder_io *reply
){
    struct svcinfo *si;
    uint16_t *s;
    size_t len;
    uint32_t handle;
    uint32_t strict_policy;
    intallow_isolated; .TXN ->code = ADD_SERVICE_TRANSACTION = 3 = SVC_MGR_ADD_SERVICE
    switch(txn->code)
    {
        ......
        case SVC_MGR_ADD_SERVICE:
            // Get the AMS name from the mOut data section
            s = bio_get_string16(msg, &len); .// Get a reference to AMS from the mOut data section (handle)
            handle = bio_get_ref(msg);
            allow_isolated = bio_get_uint32(msg) ? 1 : 0;
            // Record AMS in SM
            if (do_add_service(bs, s, len, handle, txn->sender_euid,
                allow_isolated, txn->sender_pid))
                return - 1;
            break; . }// There is no data in reply at this time
    bio_put_uint32(reply, 0);
    return 0;
}
Copy the code
do_add_service()
// frameworks/native/cmds/servicemanager/service_manager.c
int do_add_service(struct binder_state *bs,
                   const uint16_t *s, size_t len,
                   uint32_t handle, uid_t uid, int allow_isolated,
                   pid_t spid
){
    // The svcinfo structure is used to store the registered Service information in SM
    struct svcinfo *si;.// Find out if AMS is registered with SM
    si = find_svc(s, len);
    // If AMS is already registered
    if (si)
    {
        if (si->handle)
        {
            ......
            // Clear the reference (handle) of the current svcinfo record
            svcinfo_death(bs, si);
        }
        // Reassign the reference (handle) in the current svcinfo
        si->handle = handle;
    }
    else // If AMS is not registered
    {
        // Create a new svcinfo structure
        si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t)); .// Record the AMS reference (handle)
        si->handle = handle;
        si->len = len;
        // Copy the AMS information
        memcpy(si->name, s, (len + 1) * sizeof(uint16_t));
        si->name[len] = '\ 0';
        si->death.func = (void*) svcinfo_death;
        si->death.ptr = si;
        si->allow_isolated = allow_isolated;
        // Add the created svcinfo structure to svclist
        si->next = svclist;
        svclist = si;
    }
    // The BC_ACQUIRE command, handle, is sent to binder drivers via ioctl,
    // make binder_ref strongly reference the increment operation
    binder_acquire(bs, handle);
    // The BC_REQUEST_DEATH_NOTIFICATION command is sent to binder drivers via ioctl,
    // Clean up the memory
    binder_link_to_death(bs, handle, &si->death);
    return 0;
}
Copy the code

The service_manager.do_add_service function logs AMS into SM, completing the registration

Stored in SM is the name of AMS and a reference to the entity node of AMS in binder drivers (Handle)

When another process later requests AMS by accessing SM, SM will return this reference to the requester

binder_send_reply()

// frameworks/native/cmds/servicemanager/binder.c
void binder_send_reply(
    	struct binder_state *bs,
		struct binder_io *reply, // Reply is empty at this point
		binder_uintptr_t buffer_to_free, // mOut is a pointer to the starting address of the memory in the data portion
		int status // status = 0
){
    // Define a structure, data, to encapsulate the command and reply
    struct {
        uint32_t cmd_free; / / position
        binder_uintptr_t buffer;
        uint32_t cmd_reply; / / low
        struct binder_transaction_data txn;
    } __attribute__((packed)) data;

    data.cmd_free = BC_FREE_BUFFER; // Free buffer command
    data.buffer = buffer_to_free;
    data.cmd_reply = BC_REPLY; / / reply command
    data.txn.target.ptr = 0;
    data.txn.cookie = 0;
    data.txn.code = 0;
    
    // status = 0, else
    if (status)
    {
        ......
    }
    else
    {
        // Use binder_transaction_data (TXN) in data to record the address information of reply
        data.txn.flags = 0;
        data.txn.data_size = reply->data - reply->data0;
        data.txn.offsets_size = ((char*) reply->offs) - ((char*) reply->offs0);
        data.txn.data.ptr.buffer = (uintptr_t)reply->data0;
        data.txn.data.ptr.offsets = (uintptr_t)reply->offs0;
    }
    // Communicates with binder drivers to execute instructions
    binder_write(bs, &data, sizeof(data));
}
Copy the code
binder_write()
// frameworks/native/cmds/servicemanager/binder.c
int binder_write(struct binder_state *bs, void *data, size_t len)
{
    struct binder_write_read bwr;
    int res;

    bwr.write_size = len;
    bwr.write_consumed = 0;
    bwr.write_buffer = (uintptr_t) data;
    bwr.read_size = 0;
    bwr.read_consumed = 0;
    bwr.read_buffer = 0;
    
    Binder_ioctl is called by the binder driver with BINDER_WRITE_READ
    res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr); .return res;
}
Copy the code
binder_ioctl()
// kernel/drivers/staging/android/binder.c
static long binder_ioctl(struct file *filp, 
                        unsigned int cmd, // CMD is the BINDER_WRITE_READ we pass in
                        unsigned long arg // arg is the BWR we passed in
){
    // Obtain device nodes driven by binder
    struct binder_proc *proc = filp->private_data;
    struct binder_thread *thread;.// Get the binder thread
    // If the pid has already created a binder thread, return the corresponding binder thread.
    // thread->looper = BINDER_LOOPER_STATE_NEED_RETURN + BINDER_LOOPER_STATE_ENTERED
    // thread->return_error = BR_OK
    // thread->return_error2 = BR_OK
    thread = binder_get_thread(proc); .switch (cmd)
    {
        case BINDER_WRITE_READ:
            ret = binder_ioctl_write_read(filp, cmd, arg, thread); .break; . }...return ret;
}
Copy the code
binder_ioctl_write_read()
// kernel/drivers/staging/android/binder.c
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; .void __user *ubuf = (void __user *)arg;
    struct binder_write_read bwr;.// Copy the starting address of data from user space to kernel space (BWR)
    if (copy_from_user(&bwr, ubuf, sizeof(bwr)))
    {
        ret = -EFAULT;
        gotoout; }...if (bwr.write_size > 0)
    {
        // Send instructions to binder drivers
        ret = binder_thread_write(proc, thread, bwr.write_buffer, bwr.write_size, &bwr.write_consumed); . }// bwr.read_size = 0, if not matched
    if (bwr.read_size > 0) {... }... out:return ret;
}
Copy the code
binder_thread_write()
// kernel/drivers/staging/android/binder.c
static int binder_thread_write(struct binder_proc *proc,
			struct binder_thread *thread,
			binder_uintptr_t binder_buffer, // binder_buffer = the start address of data
			size_t size, // Size of data
			binder_size_t *consumed
){
    uint32_t cmd;
    struct binder_context *context = proc->context;
    void __user *buffer = (void __user *)(uintptr_t)binder_buffer;
    // A pointer to the start address of data memory
    void __user *ptr = buffer + *consumed;
    // A pointer to the end address of data memory
    void __user *end = buffer + size;
    
    while (ptr < end && thread->return_error == BR_OK)
    {
        // Read instructions from data
        if (get_user(cmd, (uint32_t __user *)ptr))
            return -EFAULT;
        // Move the pointer back
        ptr += sizeof(uint32_t);
        // start with BC_FREE_BUFFER and BC_REPLY
        switch (cmd)
        {
            ......
            case BC_FREE_BUFFER:
            {
                // The memory area pointed to by data.buffer is emptied.
                // This is the cache of the mOut data part copied into the kernel space.
                // No more analysis here.break; }...case BC_TRANSACTION:
            case BC_REPLY:
            {
                struct binder_transaction_data tr;
                // Copy the reply recorded in data from user space to kernel space (binder_transaction_data)
                if (copy_from_user(&tr, ptr, sizeof(tr)))
                    return -EFAULT;
                // Move the pointer back
                ptr += sizeof(tr);
                // Call binder_transaction
                binder_transaction(proc, thread, &tr, cmd == BC_REPLY, 0);
                break; }... }... }return 0;
}
Copy the code
binder_transaction()

The binder_transaction function is called again to communicate with the AMS process, notifying the AMS registration success

// kernel\drivers\staging\android\binder.c
static void binder_transaction(struct binder_proc *proc,
			       struct binder_thread *thread,
			       struct binder_transaction_data *tr, 
				   int reply, // This time reply = true
			       binder_size_t extra_buffers_size)
{...struct binder_transaction *t;
    struct binder_work *tcomplete;.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; .// Here reply is true (CMD == BC_REPLY)
    if (reply)
    {
        // Get binder_transaction recorded in thread->transaction_stackin_reply_to = thread->transaction_stack; . thread->transaction_stack = in_reply_to->to_parent;// in_reply_to->from = AMS threadtarget_thread = in_reply_to->from; . target_proc = target_thread->proc; }else{... }// now the target_thread! = NULL, if hit
    if (target_thread)
    {
        // Get the PID value of AMS thread
        e->to_thread = target_thread->pid;
        // Get the TOdo queue and wait queue of AMS thread
        target_list = &target_thread->todo;
        target_wait = &target_thread->wait;
    }
    else{... }...// Generate a binder_transaction variable,
    // Describes the transaction to be done (target_thread->todo).
    // So that when the target object is woken up, it can fetch work from the queue.
    t = kzalloc(sizeof(*t), GFP_KERNEL); .// Generate a binder_work variable (tcomplete) to indicate that AMS has an unfinished job
    tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL); .// If not matched, else is executed
    if(! reply && ! (tr->flags & TF_ONE_WAY)) ......else
        t->from = NULL; .// Record the target process of this communication (AMS)t->to_proc = target_proc; .// This communication code = 0
    t->code = tr->code;
    // Flags = 0t->flags = tr->flags; .// Allocate buffer from AMS process
    // To complete this transaction, allocate memory from binder_mmap.
    t->buffer = binder_alloc_buf(target_proc, tr->data_size, tr->offsets_size, extra_buffers_size, ! reply && (t->flags & TF_ONE_WAY)); .// Record AMS binder_node with target_node = NULLt->buffer->target_node = target_node; .// Copy reply from user space to kernel space (t->buffer->data)
    if (copy_from_user(t->buffer->data, (const void __user *)(uintptr_t)
                    tr->data.ptr.buffer, tr->data_size))
    ......
    CMD = BC_REPLY, reply = true
    if (reply)
    {
        ......
        // Clear the data and release the cache
        binder_pop_transaction(target_thread, in_reply_to);
    }
    else if(! (t->flags & TF_ONE_WAY)) { ...... }else{... }// Set t's type to BINDER_WORK_TRANSACTION
    t->work.type = BINDER_WORK_TRANSACTION;
    // add t to the AMS thread todo queue
    list_add_tail(&t->work.entry, target_list);
    // Set the binder_work type to BINDER_WORK_TRANSACTION_COMPLETE
    tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;
    // Add tComplete to the TOdo queue of the SM process
    list_add_tail(&tcomplete->entry, &thread->todo);
    // when AMS is suspended, target_wait! = NULL, if hit
    if (target_wait)
        // Wake up the AMS process
        wake_up_interruptible(target_wait);
    return; . }Copy the code

Binder_transaction returns all the way back to binder_loop, where the binder_loop calls ioctl again to read the binder driver’s instructions

binder_ioctl_write_read()

// kernel/drivers/staging/android/binder.c
static int binder_ioctl_write_read(struct file *filp,
				unsigned int cmd, unsigned long arg,
				struct binder_thread *thread
){
    struct binder_proc *proc =filp->private_data; .void __user *ubuf = (void __user *)arg;
    struct binder_write_read bwr;
    
    // Copy the binder_write_read structure (ubuF) describing the data from user space to kernel space (BWR)
    if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
    ......
    // bwr.write_size = 0, if not matched
    if (bwr.write_size > 0) {... }// bwr.read_size > 0, if hit
    if (bwr.read_size > 0)
    {
        // Read the instructions returned by binder drivers
        ret = binder_thread_read(proc, thread, bwr.read_buffer, bwr.read_size, &bwr.read_consumed, filp->f_flags & O_NONBLOCK); . }...return ret;
}
Copy the code

binder_thread_read()

static int binder_thread_read(struct binder_proc *proc,
			      struct binder_thread *thread,
			      binder_uintptr_t binder_buffer, size_t size,
			      binder_size_t *consumed, int non_block
){
    void __user *buffer = (void __user *)(uintptr_t)binder_buffer;
    // pointer to the starting address of bwr.read_buffer in binder_loop
    void __user *ptr = buffer + *consumed;
    // pointer to the bwr.read_buffer end address in binder_loop
    void __user *end = buffer + size;

    int ret = 0;
    intwait_for_proc_work; . retry:Thread ->todo is not empty and wait_for_proc_work is false
    Thread ->todo is empty and wait_for_proc_work is true
    wait_for_proc_work = thread->transaction_stack == NULL && list_empty(&thread->todo); .1. Execute else
    // 2. Run if
    if (wait_for_proc_work)
    {
        ......
        if (non_block) // Filp ->f_flags & O_NONBLOCK is already assigned
                       // non_block > 0, else{... }else
            If thread->todo is empty, binder_has_thread_work returns false to suspend the SM thread
            ret = wait_event_freezable_exclusive(proc->wait, binder_has_proc_work(proc, thread));
    }
    else
    {
        if (non_block) // Filp ->f_flags & O_NONBLOCK is already assigned
                       // non_block > 0, else{... }else
            Thread ->todo is not null. Binder_has_thread_work returns true. SM threads will not be suspended
            ret = wait_event_freezable(thread->wait, binder_has_thread_work(thread)); }...// 1. The thread is not suspended and continues the while loop
    while (1)
    {
        uint32_t cmd;
        struct binder_transaction_data tr;
        struct binder_work *w;
        struct binder_transaction *t = NULL;
        
        If thread->todo is null, thread->todo is null. If thread->todo is null, thread->todo is null
        BINDER_WORK_TRANSACTION_COMPLETE binder_work_complete binder_work_complete
        // If thread->todo is null, execute else
        if (!list_empty(&thread->todo))
        {
            // 1. Fetch binder_work
            w = list_first_entry(&thread->todo, struct binder_work, entry);
        }
        else
        {
            // 2
            if (ptr - buffer == 4 && !(thread->looper & BINDER_LOOPER_STATE_NEED_RETURN))
                // 2. Run the code back to the retry position
                goto retry;
            break; }...W ->type is BINDER_WORK_TRANSACTION_COMPLETE
        switch (w->type)
        {
            ......
            case BINDER_WORK_TRANSACTION_COMPLETE:
            {
                // 1. Change the directive BR_TRANSACTION_COMPLETE
                cmd = BR_TRANSACTION_COMPLETE;
                // 1. Copy the instruction to bwr.read_buffer in binder_loop
                if (put_user(cmd, (uint32_t __user *)ptr))
                    return -EFAULT;
                // 1
                ptr += sizeof(uint32_t); .// 1. Delete the current binder_work from thread->todo
                list_del(&w->entry);
                // 1. Release binder_work memory
                kfree(w); . }break; . }// 1. T = null, if hit
        if(! t)continue; . } *consumed = ptr - buffer; .return 0;
}
Copy the code

In the binder_thread_read function, the while loop executes twice, so the comments in the code indicate the ordinal number that corresponds to the number of times in the while loop

The SM is suspended again, waiting for other processes to communicate with it and wake up

When the SM wakes up, the binder_thread_read function resumes execution from there

What does the AMS process do when it wakes up?

When the binder_transaction function completes, the AMS process wakes up to continue the unfinished binder_thread_read function

binder_thread_read()
// kernel\drivers\staging\android\binder.c
static int binder_thread_read(struct binder_proc *proc,
			      struct binder_thread *thread,
			      binder_uintptr_t binder_buffer, size_t size,
			      binder_size_t *consumed, int non_block)
{...while (1)
    {
        uint32_t cmd;
        struct binder_transaction_data tr;
        struct binder_work *w;
        struct binder_transaction *t = NULL; .// Add a binder_transaction to the binder_transaction function, proc->todo is not null
        else if (!list_empty(&proc->todo) && wait_for_proc_work)
        {
            // Fetch binder_transaction, but of type binder_work
            w = list_first_entry(&proc->todo, struct binder_work, entry); }...W ->type is BINDER_WORK_TRANSACTION
        switch (w->type)
        {
            ......
            case BINDER_WORK_TRANSACTION:
            {
                // Type conversion (binder_work -> binder_transaction)
                t = container_of(w, struct binder_transaction, work);
            } break; . }// t! = null, if not hit
        if(! t)continue; .// when t->buffer->target_node is null, if is not hit
        if (t->buffer->target_node)
        {
            ......
        }
        else
        {
            tr.target.ptr = 0;
            tr.cookie = 0;
            // The directive changes to BR_REPLY
            cmd = BR_REPLY;
        }
        
        // t->code = 0
        tr.code = t->code;
        // t->flags = 0
        tr.flags = t->flags;
        
        T ->from = NULL
        if (t->from)
        {
            ......
        }
        else
        {
            tr.sender_pid = 0;
        }
        // Record the start address and size of the memory in reply
        tr.data_size = t->buffer->data_size;
        tr.offsets_size = t->buffer->offsets_size;
        tr.data.ptr.buffer = (binder_uintptr_t) ((uintptr_t)t->buffer->data + 
                                                proc->user_buffer_offset);
        tr.data.ptr.offsets = tr.data.ptr.buffer + 
            	ALIGN(t->buffer->data_size, sizeof(void *));
        
        // Copy the directive BR_REPLY to user space (mIn)
        if (put_user(cmd, (uint32_t __user *)ptr))
            return -EFAULT;
        // Move the pointer back
        ptr += sizeof(uint32_t);
        
        // Copy the reply information to user space (mIn)
        if (copy_to_user(ptr, &tr, sizeof(tr)))
            return -EFAULT;
        // Move the pointer back
        ptr += sizeof(tr); .// If does not match
        if(cmd == BR_TRANSACTION && ! (t->flags & TF_ONE_WAY)) { ...... }else
        {
            t->buffer->transaction = NULL;
            // Free memory
            kfree(t);
        }
        // Break the loop
        break; . } *consumed = ptr - buffer; .return 0;
}
Copy the code

Binder_thread_read function, after the completion of execution has been returned to the IPCThreadState: : talkWithDriver () function, to continue

IPCThreadState::talkWithDriver()

// android\frameworks\native\libs\binder\IPCThreadState.cpp
status_t IPCThreadState::talkWithDriver(bool doReceive)
{...do{...// execute the return
        if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
            err = NO_ERROR;
        elseerr = -errno; . }while (err == -EINTR); If no ioctl error occurs, exit the loop.// If no ioctl error occurs, if hits
    if (err >= NO_ERROR)
    {
        // If the mOut data is already sent to the Binder driver
        if (bwr.write_consumed > 0)
        {
            if (bwr.write_consumed < mOut.dataSize())
                // Delete the data already sent in mOut
                mOut.remove(0, bwr.write_consumed);
            else
                mOut.setDataSize(0);
        }

        // If there is data in mIn, return all mIn
        if (bwr.read_consumed > 0)
        {
            mIn.setDataSize(bwr.read_consumed);
            mIn.setDataPosition(0); }...return NO_ERROR;
    }
    
    return err;
}
Copy the code

IPCThreadState::waitForResponse()

// android\frameworks\native\libs\binder\IPCThreadState.cpp
status_t IPCThreadState::waitForResponse(
                    Parcel *reply, / / reply = ServiceManagerProxy addSevice in reply
                                   // This reply is in user space
                    status_t *acquireResult
){
    uint32_t cmd;
    int32_t err;
    // Loop to wait for results
    while (1) {...// Read the instructions in mIn (BR_REPLY)
        cmd = (uint32_t)mIn.readInt32(a); .switch(cmd)
        {
            ......
            case BR_REPLY:
            {
                binder_transaction_data tr;
                // Read the message from reply (in kernel space)
                err = mIn.read(&tr, sizeof(tr)); .// Reply (in user space) is not empty, if hit
                if (reply)
                {
                    // Tr. flags = 0, if hit
                    if ((tr.flags & TF_STATUS_CODE) == 0)
                    {
                        Write reply (in kernel space) to reply (in user space),
                        . / / that is written to ServiceManagerProxy addSevice in reply
                        reply->ipcSetDataReference(
                                reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
                                tr.data_size,
                                reinterpret_cast<const binder_size_t*> 
                            			(tr.data.ptr.offsets),
                                tr.offsets_size/sizeof(binder_size_t),
                                freeBuffer, this);
                    }
                    else{... }}else{... }}// Break the loop
            gotofinish; . } } finish:if(err ! = NO_ERROR) {if (acquireResult) *acquireResult = err;
        if (reply) reply->setError(err);
        mLastError = err;
    }
    return err;
}
Copy the code

When IPCThreadState: : waitForResponse function, after the completion of execution has been returned to ServiceManagerProxy. AddSevice function, to continue

ServiceManagerProxy.addSevice()

// frameworks/base/core/java/android/os/ServiceManagerNative$ServiceManagerProxy.java
public void addService(String name, IBinder service, boolean allowIsolated) 
		throws RemoteException
{...// execute the return
    mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply, 0);
    // Recycle data and reply
    reply.recycle();
    data.recycle();
}
Copy the code

At this point, the whole process ends

conclusion

In accordance with the order of instructions, the AMS registration process is roughly shown as follows

According to the order of the call stack, the AMS registration process is roughly shown below

It might be a little clearer if you look at the code flow with the flow chart