Binder Analysis – Overall overview

Binder Analysis — AMS registration Process

This blog is a complement to my previous blog, Binder Analysis – AMS Registration Process. The overall process is not very different from the AMS registration process, but there are some details that need to be noted

(The following analysis is Android 6.0 source code)

How does the APP process get AMS?

BindService call process, for example, access to AMS from ContextImpl. BindServiceCommon () function

(This is just the process of getting AMS, not bindService.)

The call stack is as follows:

ContextImpl.bindService()

–> ContextImpl.bindServiceCommon()

–> ActivityManagerNative.getDefault()

–> ServiceManager.getService("activity")

–> ServiceManager.getIServiceManager()

–> ServiceManagerProxy.getService()

ContextImpl.bindService()

// frameworks/base/core/java/android/app/ContextImpl.java
public boolean bindService(Intent service, ServiceConnection conn, int flags)
{...return bindServiceCommon(service, conn, flags, Process.myUserHandle());
}
Copy the code

ContextImpl.bindServiceCommon()

// 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

ActivityManagerNative.getDefault()

// frameworks/base/core/java/android/app/ActivityManagerNative.java
static public IActivityManager getDefault(a)
{
    return gDefault.get();
}

private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>()
{
    protected IActivityManager create(a)
    {
        IBinder b = ServiceManager.getService("activity"); . IActivityManager am = asInterface(b); .returnam; }};Copy the code

Singleton is a Singleton class. When singleton.get () is called externally, the internal singleton.create () function is called to create the Singleton if the corresponding generic object is not created

ServiceManager.getService(“activity”)
// frameworks/base/core/java/android/os/ServiceManager.java
public static IBinder getService(String name)
{... getIServiceManager().getService(name); . }Copy the code

ServiceManager. GetIServiceManager function in a blog post on introduction, have not repeat here

portal

ServiceManagerProxy.getService()
// frameworks/base/core/java/android/os/ServiceManagerNative$ServiceManagerProxy.java
public IBinder getService(String name)
{
    / / 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);
    // mRemote = BinderProxy, equivalent to calling binderproxy.transact
    mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
    IBinder binder = reply.readStrongBinder();
    reply.recycle();
    data.recycle();
    return binder;
}
Copy the code

How does the APP process send data to SM?

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

The 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 last blog post and won’t be repeated here

portal

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

What does the SM process do when it wakes up?

When the SM process is woken up, it resumes the unfinished binder_thread_read function

The call stack is as follows:

binder_thread_read()

–> binder_loop()

–> binder_parse()

–> service_manager.svcmgr_handler()

–> binder_send_reply()

–> binder_ioctl_write_read()

–> binder_thread_read()

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

portal

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 = GET_SERVICE_TRANSACTION = 1 = SVC_MGR_GET_SERVICE
    switch(txn->code)
    {
        ......
        case SVC_MGR_GET_SERVICE:
        case SVC_MGR_CHECK_SERVICE:
            // Get the AMS name from the mOut data section
            s = bio_get_string16(msg, &len); .// Get the AMS reference by the AMS name (handle)
            handle = do_find_service(bs, s, len, txn->sender_euid, txn->sender_pid); .// Build a flat_binder_object and write an AMS reference (handle) to it to encapsulate it.
            // Write flat_binder_object to reply
            bio_put_ref(reply, handle);
            return 0; . }}Copy the code

do_find_service()

// frameworks/native/cmds/servicemanager/service_manager.c
uint32_t do_find_service(struct binder_state *bs, 
                         const uint16_t *s, size_t len, uid_t uid, pid_t spid
){
    // If AMS is registered with SM, return the saved Service information
    struct svcinfo *si = find_svc(s, len); .// Return a reference to AMS (handle)
    return si->handle;
}
Copy the code

bio_put_ref()

// frameworks/native/cmds/servicemanager/binder.c
void bio_put_ref(
    	struct binder_io *bio, // reply
    	uint32_t handle
){
    struct flat_binder_object *obj;
    // If hits
    if (handle)
        // Create a flat_binder_object and write flat_binder_object to reply
        obj = bio_alloc_obj(bio);
    else
        obj = bio_alloc(bio, sizeof(*obj));

    if(! obj)return;

    obj->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
    obj->type = BINDER_TYPE_HANDLE;
    // Write the AMS reference (handle) to the flat_binder_object
    obj->handle = handle;
    obj->cookie = 0;
}
Copy the code

What does the APP process do when it wakes up?

The APP process wakes up and resumes the unfinished binder_thread_read function

Return the stack as follows:

binder_thread_read()

–> binder_ioctl_write_read()

–> IPCThreadState::talkWithDriver()

–> IPCThreadState::waitForResponse()

–> IPCThreadState::transact()

–> BinderProxy.transact()

–> ServiceManagerProxy.getService()

–> reply.readStrongBinder()

–> ServiceManager.getService("activity")

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

portal

reply.readStrongBinder()

// frameworks/base/core/java/android/os/Parcel.java
public final IBinder readStrongBinder(a)
{
    return nativeReadStrongBinder(mNativePtr);
}

// frameworks/base/core/jni/android_os_Parcel.cpp
static const JNINativeMethod gParcelMethods[] = {
    ......
    {"nativeReadStrongBinder"."(J)Landroid/os/IBinder;", (void*)android_os_Parcel_readStrongBinder},
    ......
}

static jobject android_os_Parcel_readStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr ){
    // Cast Java layer Parcel type to Native layer Parcel type.
    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
    if(parcel ! = NULL) {return javaObjectForIBinder(env, parcel->readStrongBinder());
    }
    return NULL;
}
Copy the code

Parcel::readStrongBinder()

// frameworks/native/libs/binder/Parcel.cpp
sp<IBinder> Parcel::readStrongBinder(a) const
{
    sp<IBinder> val;
    unflatten_binder(ProcessState::self* ()this, &val);
    return val;
}

status_t unflatten_binder(const sp<ProcessState>& proc,
                          const Parcel& in, // reply
                          sp<IBinder>* out
){
    // Read flat_binder_object from reply
    const flat_binder_object* flat = in.readObject(false);
    // If hits
    if (flat)
    {
        Flat ->type = BINDER_TYPE_HANDLE
        switch (flat->type)
        {
            // The process that requests Service belongs to the same process as Service
            case BINDER_TYPE_BINDER:
                *out = reinterpret_cast<IBinder*>(flat->cookie);
                return finish_unflatten_binder(NULL, *flat, in);
            // The process that requests a Service belongs to a different process
            case BINDER_TYPE_HANDLE:
                // Create a BpBinder object
                *out = proc->getStrongProxyForHandle(flat->handle);
                return finish_unflatten_binder(static_cast<BpBinder*>(out->get()), *flat, in); }}return BAD_TYPE;
}
Copy the code

ProcessState::getStrongProxyForHandle()

// frameworks/native/libs/binder/ProcessState.cpp
sp<IBinder> ProcessState::getStrongProxyForHandle(
    	int32_t handle // AMS reference (handle)
){ sp<IBinder> result; .// Create the BpBinder object, handle is AMS
    b = new BpBinder(handle); . result = b; .return result;
}
Copy the code

finish_unflatten_binder()

// frameworks/native/libs/binder/Parcel.cpp
inline static status_t finish_unflatten_binder(
    BpBinder* /*proxy*/.const flat_binder_object& /*flat*/.const Parcel& /*in*/)
{
    return NO_ERROR;
}
Copy the code

Parcel::readStrongBinder()The function creates a BpBinder object whose Handle is AMS

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
    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

The BinderProxy object binds to BpBinder objects that correspond to AMS

reply.readStrongBinder()The function returns a BinderProxy object that binds a BpBinder object (corresponding to AMS) to the Native layer.

conclusion

According to the order of the call stack, the AMS acquisition process is roughly shown as follows

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