Binder Analysis – Overall overview

Binder Analysis — AMS registration Process

Binder analysis — AMS acquisition process

Binder mechanism is the underlying principle for implementing IPC in Android and is usually only used in system source code

We Android developers usually do application-layer development, and when we want to do IPC, Binder mechanisms are too cumbersome to use directly

So Google came up with AIDL for us

The Android Interface Definition Language (AIDL) is a Binder mechanism that encapsulates the application layer and enables IPC communication

This blog will explain the AIDL invocation process

(The following analysis is Android 6.0 source code)

How does the APP process send data to AMS?

Immediately after the last blog, the APP process AIDL called AMS Service binding Service as an example for analysis

// frameworks/base/core/java/android/app/ContextImpl.java
private boolean bindServiceCommon(Intent service, ServiceConnection conn, 
                                  int flags, UserHandle user
){...int res = ActivityManagerNative.getDefault().bindService(
            mMainThread.getApplicationThread(), getActivityToken(), service,
            service.resolveTypeIfNeeded(getContentResolver()),
            sd, flags, getOpPackageName(), user.getIdentifier());
    if (res < 0)
    {
        throw new SecurityException(
                "Not allowed to bind to service " + service);
    }
    returnres ! =0; . }Copy the code

We’ve learned through on a blog, eventually ActivityManagerNative. GetDefault () function returns a ActivityManagerProxy object

// frameworks/base/core/java/android/app/ActivityManagerNative$ActivityManagerProxy.java
public int bindService(IApplicationThread caller, IBinder token,
            Intent service, String resolvedType, IServiceConnection connection,
            int flags, String callingPackage, int userId
){
    / / create the data
    Parcel data = Parcel.obtain();
    / / create the reply
    Parcel reply = Parcel.obtain();
    data.writeInterfaceToken(IActivityManager.descriptor);
    // Write ApplicationThread to datadata.writeStrongBinder(caller ! =null ? caller.asBinder() : null);
    data.writeStrongBinder(token);
    service.writeToParcel(data, 0);
    data.writeString(resolvedType);
    // Write ServiceConnection to data
    data.writeStrongBinder(connection.asBinder());
    data.writeInt(flags);
    data.writeString(callingPackage);
    data.writeInt(userId);
    // mRemote = BinderProxy, equivalent to calling binderproxy.transact
    mRemote.transact(BIND_SERVICE_TRANSACTION, data, reply, 0);
    reply.readException();
    int res = reply.readInt();
    data.recycle();
    reply.recycle();
    return res;
}
Copy the code

The next call stack is as follows:

BinderProxy.transact()

–> BpBinder::transact()

–> IPCThreadState::transact()

–> IPCThreadState::waitForResponse()

–> IPCThreadState::talkWithDriver()

–> binder_ioctl_write_read()

–> binder_thread_write()

–> binder_transaction()

–> binder_thread_read()

Most of them were covered in the second blog post and won’t be repeated here

portal

The call flow is the same except for the data in mOut

Eventually the APP thread will be suspended, waiting for the AMS process to return data and wake up

How is the AMS process started?

The AMS service runs in the system_server Process, which is a Java layer Process and is created through the process.start () function

Using the process.start () function, the Zygote Process is sent a socket message to create the Process

Zygote receives the message and calls the zygote.forkandWte () function to fork the new process

Through the Process. The start () function creates a new Process, at the time of initialization is called RuntimeInit. NativeZygoteInit () function, the function through JNI mapping, The onZygoteInit function in app_main.cpp is eventually called

onZygoteInit()

// frameworks/base/cmds/app_process/app_main.cpp
virtual void onZygoteInit(a)
{
    sp<ProcessState> proc = ProcessState::self(a);ALOGV("App process: starting thread pool.\n");
    proc->startThreadPool(a); }Copy the code

The ProcessState::self() function, described in the previous blog, creates the ProcessState object (singleton), opens the Binder driver, and maps a portion of the kernel’s address space as a buffer through Mmap

ProcessState::startThreadPool()

// frameworks/native/libs/binder/ProcessState.cpp
void ProcessState::startThreadPool(a)
{
    AutoMutex _l(mLock); // Concurrent lock, multithreading synchronization
    if(! mThreadPoolStarted) { mThreadPoolStarted =true;
        spawnPooledThread(true); }}Copy the code

When the Binder device is started, the Binder thread pool is started and mThreadPoolStarted = true is set

The mThreadPoolStarted variable is used to ensure that only one Binder thread pool is started per application process

ProcessState::spawnPooledThread()

// frameworks/native/libs/binder/ProcessState.cpp
void ProcessState::spawnPooledThread(bool isMain)
{
    if (mThreadPoolStarted)
    {
        // Get the Binder thread name in the format Binder_x, where x is an integer;
        // The x in each process starts at 1 and increases, so Binder_1 is the main thread
        String8 name = makeBinderThreadName(a);ALOGV("Spawning new pooled thread, name=%s\n", name.string());

        // Create a Binder thread
        sp<Thread> t = new PoolThread(isMain);
        t->run(name.string()); }}Copy the code

ProcessState: : spawnPooledThread used to create the Binder thread, through parameter isMain is created to distinguish the main thread or common threads

The Binder main thread (isMain = true) is created. Binder normal threads are created by the Binder driver

On the Binder thread name, only by ProcessState: : spawnPooledThread () function creates a thread to conform to the format, For direct current thread through IPCThreadState: : joinThreadPool () function to join the thread pool threads are not conform to the naming format

Binder:< PID >_x format has been changed since Android 7.0 to Binder:< PID >_x format. Binder thread name pid field can be used to quickly locate the process that the Binder thread belongs to

PoolThread::run()
// frameworks/native/libs/binder/ProcessState.cpp
class PoolThread : public Thread
{
public:
    PoolThread(bool isMain)
        : mIsMain(isMain)
    {
    }
    
protected:
    virtual bool threadLoop(a)
    {
        IPCThreadState::self() - >joinThreadPool(mIsMain);
        return false;
    }
    
    const bool mIsMain;
};

// system/core/include/utils/Thread.h
class Thread : virtual public RefBase
{
public:...virtual status_t run(const char* name = 0.int32_t priority = PRIORITY_DEFAULT, 
                         size_t stack = 0); . }Copy the code

PoolThread inherits the Thread class, which is essentially a Thread, t->run(name.string()); This line calls the threadLoop() function in PoolThread

IPCThreadState::joinThreadPool()
// frameworks/native/libs/binder/IPCThreadState.cpp
void IPCThreadState::joinThreadPool(bool isMain)
{...// if isMain = true, write mOut to BC_ENTER_LOOPER
    mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
    
    // Set the current Binder thread to the foreground thread
    set_sched_policy(mMyThreadId, SP_FOREGROUND);
        
    status_t result;
    do{...// Handle instructions given by Binder drivers
        result = getAndExecuteCommand(a); .// If the thread is no longer needed and it is not the main thread, let it exit the thread pool
        if(result == TIMED_OUT && ! isMain) {break; }}while(result ! = -ECONNREFUSED && result ! = -EBADF); . }Copy the code
IPCThreadState::getAndExecuteCommand()
// frameworks/native/libs/binder/IPCThreadState.cpp
status_t IPCThreadState::getAndExecuteCommand(a)
{
    status_t result;
    int32_t cmd;

    // Communicate with Binder drivers
    result = talkWithDriver(a); . }Copy the code

IPCThreadState: : talkWithDriver blog before () function has been introduced, the main is to build binder_write_read structure, through the system call to the Binder driven binder_ioctl () function, into the kernel

It is worth noting that IPCThreadState: : talkWithDriver () function parameter’s default value is true, That is, calling Binder drivers with this function fires both binder_thread_write() and binder_thread_read() by default

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 mOut
			size_t size, // The length of mOut
			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 starting 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)
    {
        // Read instructions from mOut, 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
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 mIn memory
    void __user *ptr = buffer + *consumed;
    // Pointer to the end address of mIn 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 Binder main thread is suspended and waits for another process to communicate with the AMS process to wake it up

The Binder main thread resumes execution of the unfinished binder_thread_read function here

The structure of mIn is as follows

What does the AMS process do when it wakes up?

When the APP process sends data to AMS, the Binder main thread in the AMS process 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 = AMS, 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 = BIND_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 APP thread and record it
            tr.sender_pid = task_tgid_nr_ns(sender, task_active_pid_ns(current));
        }
        else{... }// Record the memory address and size of the data sent by the APP process
        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 to user space (mIn)
        if (put_user(cmd, (uint32_t __user *)ptr))
            return -EFAULT;
        // Move the pointer back
        ptr += sizeof(uint32_t);
        
        // Copy mOut data to user space (mIn)
        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;// Save t in transaction_stack of AMS main thread
            thread->transaction_stack = t;
        }
        else{... }// Break the loop
        break; . } done: *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 command BR_SPAWN_LOOPER to user space (mIn)
        if (put_user(BR_SPAWN_LOOPER, (uint32_t __user *)buffer))
            return-EFAULT; . }return 0;
}
Copy the code

When binder_thread_read () function, after the completion of execution binder_ioctl_write_read () function is executed, returns to the IPCThreadState: : getAndExecuteCommand () function, to continue

The structure of mIn is as follows

IPCThreadState::getAndExecuteCommand()

// frameworks/native/libs/binder/IPCThreadState.cpp
status_t IPCThreadState::getAndExecuteCommand(a)
{
    status_t result;
    int32_t cmd;

    // execute the return
    result = talkWithDriver(a);if (result >= NO_ERROR)
    {
        // The length of data in mIn
        size_t IN = mIn.dataAvail(a);if (IN < sizeof(int32_t)) return result;
        // Read the instructions in mIn
        cmd = mIn.readInt32(a); .// Execute the instructions given by the Binder driver
        result = executeCommand(cmd); .// Set the current Binder thread to the foreground thread
        set_sched_policy(mMyThreadId, SP_FOREGROUND);
    }

    return result;
}
Copy the code

IPCThreadState: : getAndExecuteCommand () function performs the IPCThreadState: : joinThreadPool do – while loop () function, only when the Binder threads are no longer needed, The Binder thread is removed from the Binder thread pool

Each loop, will be called IPCThreadState: : talkWithDriver () function and Binder driven communications, IPCThreadState: : talkWithDriver all the data of each time will be mIn () function to return

Inside the Parcel::readInt32() function, the location of an instruction is recorded in the mDataPos field. Each call returns the currently read instruction and increments the mDataPos field

// frameworks/native/libs/binder/Parcel.cpp
int32_t Parcel::readInt32(a) const
{
    return readAligned<int32_t> (); }template<class T>
T Parcel::readAligned(a) const
{
    T result;
    if (readAligned(&result) ! = NO_ERROR) { result =0;
    }
    return result;
}

template<class T>
status_t Parcel::readAligned(T *pArg) const
{
    COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE_UNSAFE(sizeof(T)) == sizeof(T));

    if ((mDataPos+sizeof(T)) <= mDataSize)
    {
        const void* data = mData+mDataPos;
        mDataPos += sizeof(T);
        *pArg =  *reinterpret_cast<const T*>(data);
        return NO_ERROR;
    }
    else
    {
        returnNOT_ENOUGH_DATA; }}Copy the code

IPCThreadState::executeCommand()

Order in which instructions are processed in mIn:

  1. BR_SPAWN_LOOPER
  2. BR_NOOP
  3. BR_TRANSACTION
// frameworks/native/libs/binder/IPCThreadState.cpp
status_t IPCThreadState::executeCommand(int32_t cmd)
{
    BBinder* obj;
    RefBase::weakref_type* refs;
    status_t result = NO_ERROR;

    switch ((uint32_t)cmd)
    {
        ......

        case BR_TRANSACTION: / / 3
        {
            binder_transaction_data tr;
            // Read the data sent by APP process in mIn
            result = mIn.read(&tr, sizeof(tr)); . Parcel buffer;// Write data to buffer
            buffer.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); . Parcel reply;status_terror; .// tr.target. PTR = weak reference to AMS kernel node
            if (tr.target.ptr)
            {
                // Get a strong reference to the AMS kernel node
                if (reinterpret_cast<RefBase::weakref_type*>(tr.target.ptr)->
                    attemptIncStrong(this))
                {
                    // tr.cookie = JavaBBinder (AMS)
                    // Call JavaBBinder's transact function
                    error = reinterpret_cast<BBinder*>(tr.cookie)->
                            transact(tr.code, buffer, &reply, tr.flags);
                    // Remove strong references to AMS kernel nodes
                    reinterpret_cast<BBinder*>(tr.cookie)->decStrong(this);
                }
                else{ error = UNKNOWN_TRANSACTION; }}else{... }// If oneway is used, then if hits
            if ((tr.flags & TF_ONE_WAY) == 0)
            {
                LOG_ONEWAY("Sending reply to %d!", mCallingPid);
                if (error < NO_ERROR)
                    reply.setError(error);
                // Immediately send reply to the APP to wake up the APP process
                sendReply(reply, 0);
            }
            else
            {
                LOG_ONEWAY("NOT sending reply to %d!", mCallingPid); }... }break; .case BR_NOOP: / / 2
            break;
        case BR_SPAWN_LOOPER: / / 1
            // Create a new Binder thread
            mProcess->spawnPooledThread(false);
            break; . }...return result;
}
Copy the code
  1. The main thread handles this instruction (BR_SPAWN_LOOPER)

    By ProcessState: : spawnPooledThread () function to create a new Binder threads

    The new thread starts, will perform IPCThreadState: : joinThreadPool () function to add a new thread to Binder thread pool

    In IPCThreadState: : joinThreadPool () function, will set a new thread to the foreground thread

    Since The Android system uses preemptive multitasking CPU scheduling, new threads will preempt the CPU slice of the main thread to execute

  2. The new thread processes the instruction (BR_NOOP)

    No processing, return directly

  3. A new thread processes the instruction (BR_TRANSACTION)

    Receives data from the APP process

    JavaBBinder inherits from BBinder, which is equivalent to calling the parent BBinder::transact() function

BBinder::transact()

// frameworks/native/libs/binder/Binder.cpp
status_t BBinder::transact(
	uint32_t code, // code = BIND_SERVICE_TRANSACTION
        const Parcel& data, // data = data sent by the APP process
        Parcel* reply, 
        uint32_t flags
){
    data.setDataPosition(0);

    status_t err = NO_ERROR;

    // code = BIND_SERVICE_TRANSACTION
    switch (code)
    {
        case PING_TRANSACTION:
            reply->writeInt32(pingBinder());
            break;
        default:
            // Call JavaBBinder's onTransact function
            err = onTransact(code, data, reply, flags);
            break;
    }

    if(reply ! =NULL)
    {
        reply->setDataPosition(0);
    }

    return err;
}
Copy the code
JavaBBinder::onTransact()
// frameworks/base/core/jni/android_util_Binder.cpp

const char* const kBinderPathName = "android/os/Binder";

static int int_register_android_os_Binder(JNIEnv* env)
{... gBinderOffsets.mExecTransact =GetMethodIDOrDie(env, clazz, "execTransact"."(IJJI)Z"); . }virtual status_t onTransact(
        uint32_t code, // code = BIND_SERVICE_TRANSACTION
        const Parcel& data, // data = data sent by the APP process
    	Parcel* reply, 
    	uint32_t flags = 0
){...// mObject = AMS object
    . / / gBinderOffsets mExecTransact = android/OS/Binder execTransact function
    // code = BIND_SERVICE_TRANSACTION
    // Call the AMS execTransact function
    jboolean res = env->CallBooleanMethod(mObject, 
                                          gBinderOffsets.mExecTransact, 
                                          code, reinterpret_cast<jlong>(&data), 
                                          reinterpret_cast<jlong>(reply), flags); .returnres ! = JNI_FALSE ? NO_ERROR : UNKNOWN_TRANSACTION; }Copy the code

AMS inherits from ActivityManagerNative, which inherits from Binder and is equivalent to calling the binder.exectransact () function of the superparent class

Binder.execTransact()
// frameworks/base/core/java/android/os/Binder.java
private boolean execTransact(int code, long dataObj, long replyObj, int flags)
{
    / / create the data
    Parcel data = Parcel.obtain(dataObj);
    / / create the reply
    Parcel reply = Parcel.obtain(replyObj);

    booleanres; .// Call ActivityManagerNative's onTransact functionres = onTransact(code, data, reply, flags); . reply.recycle(); data.recycle(); .return res;
}
Copy the code
ActivityManagerNative.onTransact()
// frameworks/base/core/java/android/app/ActivityManagerNative.java
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
{
    // code = BIND_SERVICE_TRANSACTION
    switch (code)
    {
        ......

        case BIND_SERVICE_TRANSACTION:
            {
            	data.enforceInterface(IActivityManager.descriptor);
            	IBinder b = data.readStrongBinder();
            	IApplicationThread app = ApplicationThreadNative.asInterface(b);
            	IBinder token = data.readStrongBinder();
            	Intent service = Intent.CREATOR.createFromParcel(data);
            	String resolvedType = data.readString();
            	b = data.readStrongBinder();
            	int fl = data.readInt();
            	String callingPackage = data.readString();
            	int userId = data.readInt();
            	IServiceConnection conn = IServiceConnection.Stub.asInterface(b);
                // call AMS's bindService function
            	int res = bindService(app, token, service, resolvedType, conn, 
                                      fl, callingPackage, userId);
            	reply.writeNoException();
            	reply.writeInt(res);
            	return true; }... }return super.onTransact(code, data, reply, flags);
}
Copy the code

After ActivityServiceManager. BindService () function is binding Service process, here will not continue to expand

IPCThreadState::sendReply()

// frameworks/native/libs/binder/IPCThreadState.cpp
status_t IPCThreadState::sendReply(const Parcel& reply, uint32_t flags)
{
    status_t err;
    status_t statusBuffer;
    // Collate the data and write the instructions BC_REPLY and reply together to mOut
    err = writeTransactionData(BC_REPLY, flags, - 1.0, reply, &statusBuffer);
    if (err < NO_ERROR) 
        return err;
    // Communicate with Binder drivers
    return waitForResponse(NULL.NULL);
}
Copy the code

IPCThreadState: : waitForResponse blog before () function has been introduced, the main is to call IPCThreadState: : talkWithDriver communicate with BInder drive () function

When BC_REPLY is sent to the Binder driver, the Binder driver’s binder_transaction() function is called to wake up the APP process and send reply to the APP process

This part of the process is similar to the execution of the binder_send_reply() function described in the second blog post for reference

What does the APP process do when it wakes up?

When the binder_transaction function completes, the APP process wakes up and continues with the unfinished binder_thread_read function

What does the process do when it wakes up compared to the AMS process described in the second blog? This part is pretty much the same

Because our analysis is the process of APP AIDL call AMS Service binding Service process, thus finally returned to ContextImpl. BindServiceCommon () function

// frameworks/base/core/java/android/app/ContextImpl.java
private boolean bindServiceCommon(Intent service, ServiceConnection conn, 
                                  int flags, UserHandle user
){...// execute the return
    int res = ActivityManagerNative.getDefault().bindService(
                mMainThread.getApplicationThread(), getActivityToken(), service,
                service.resolveTypeIfNeeded(getContentResolver()),
                sd, flags, getOpPackageName(), user.getIdentifier());
    if (res < 0)
    {
        throw new SecurityException(
                "Not allowed to bind to service " + service);
    }
    returnres ! =0; . }Copy the code

At this point, the entire AIDL call process ends

conclusion

(The overall flow chart of AIDL calls will be added later)