当前位置:网站首页>(O) Analysis of service manager (1) BinderInternal.getContextObject

(O) Analysis of service manager (1) BinderInternal.getContextObject

2020-11-08 16:12:42 Tianwang gaidihu 626

1. Binder, JNI Function registration
Based on the analysis of BinderInternal Of getContextObject Function before , Let's take a look first Binder in JNI Function registration

android_os_Binder.cpp

int register_android_os_Binder(JNIEnv* env)
{
    // Leo, register Binder Correlation JNI function
    if (int_register_android_os_Binder(env) < 0)
        return -1;
    // Leo, register Binderinternal Correlation JNI function
    if (int_register_android_os_BinderInternal(env) < 0)
        return -1;
    // Leo, register BinderProxy Correlation JNI function
    if (int_register_android_os_BinderProxy(env) < 0)
        return -1;
 
    jclass clazz = FindClassOrDie(env, "android/util/Log");
    gLogOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
    gLogOffsets.mLogE = GetStaticMethodIDOrDie(env, clazz, "e",
            "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;)I");
 
    clazz = FindClassOrDie(env, "android/os/ParcelFileDescriptor");
    gParcelFileDescriptorOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
    gParcelFileDescriptorOffsets.mConstructor = GetMethodIDOrDie(env, clazz, "<init>",
                                                                 "(Ljava/io/FileDescriptor;)V");
 
    clazz = FindClassOrDie(env, "android/os/StrictMode");
    gStrictModeCallbackOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
    gStrictModeCallbackOffsets.mCallback = GetStaticMethodIDOrDie(env, clazz,
            "onBinderStrictModePolicyChange", "(I)V");
 
    return 0;
}
As for why we started to go this way , We are not going to discuss
This method , Mainly , Called each of the register Method , Registered a few JNI function , So how to register , Let's go into the method and see , First look at int_register_android_os_Binder
static const JNINativeMethod gBinderMethods[] = {
     /* name, signature, funcPtr */
    { "getCallingPid", "()I", (void*)android_os_Binder_getCallingPid },
    { "getCallingUid", "()I", (void*)android_os_Binder_getCallingUid },
    { "clearCallingIdentity", "()J", (void*)android_os_Binder_clearCallingIdentity },
    { "restoreCallingIdentity", "(J)V", (void*)android_os_Binder_restoreCallingIdentity },
    { "setThreadStrictModePolicy", "(I)V", (void*)android_os_Binder_setThreadStrictModePolicy },
    { "getThreadStrictModePolicy", "()I", (void*)android_os_Binder_getThreadStrictModePolicy },
    { "flushPendingCommands", "()V", (void*)android_os_Binder_flushPendingCommands },
    { "init", "()V", (void*)android_os_Binder_init },
    { "destroy", "()V", (void*)android_os_Binder_destroy },
    { "blockUntilThreadAvailable", "()V", (void*)android_os_Binder_blockUntilThreadAvailable }
};
 
const char* const kBinderPathName = "android/os/Binder";
 
static int int_register_android_os_Binder(JNIEnv* env)
{
    jclass clazz = FindClassOrDie(env, kBinderPathName);
 
    gBinderOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
    gBinderOffsets.mExecTransact = GetMethodIDOrDie(env, clazz, "execTransact", "(IJJI)Z");
    gBinderOffsets.mObject = GetFieldIDOrDie(env, clazz, "mObject", "J");
 
    return RegisterMethodsOrDie(
        env, kBinderPathName,
        gBinderMethods, NELEM(gBinderMethods));
}
static struct bindernative_offsets_t
{
    // Class state.
    jclass mClass;
    jmethodID mExecTransact;
 
    // Object state.
    jfieldID mObject;
 
} gBinderOffsets;
that , From this method , We can see , take gBinderOffsets and Java The world android.os.Binder class , Association , And specify
gBinderOffsets.mClass by android.os.Binder class

gBinderOffsets.mExecTransact by android.os.Binder.execTransact Method

gBinderOffsets.mObject Corresponding to android.os.Binder Of mObject The value of the object

also , take gBinderMethods Corresponding to Java The way of the world and C The corresponding methods of the world correspond to each other

So the other two methods mentioned above , The goal achieved is also consistent with the above method , We can draw the following other conclusions

1). BinderInternal

static const JNINativeMethod gBinderInternalMethods[] = {
     /* name, signature, funcPtr */
    // Leo, take android_os_BinderInternal_getContextObject Methods and com.android.internal.os.BinderInternal.getContextObject Method to bind
    { "getContextObject", "()Landroid/os/IBinder;", (void*)android_os_BinderInternal_getContextObject },
    // Leo, take android_os_BinderInternal_joinThreadPool Methods and com.android.internal.os.BinderInternal.joinThreadPool Method to bind
    { "joinThreadPool", "()V", (void*)android_os_BinderInternal_joinThreadPool },
    // Leo, take android_os_BinderInternal_disableBackgroundScheduling Methods and com.android.internal.os.BinderInternal.disableBackgroundScheduling Method to bind
    { "disableBackgroundScheduling", "(Z)V", (void*)android_os_BinderInternal_disableBackgroundScheduling },
    // Leo, take android_os_BinderInternal_setMaxThreads Methods and com.android.internal.os.BinderInternal.setMaxThreads Method to bind
    { "setMaxThreads", "(I)V", (void*)android_os_BinderInternal_setMaxThreads },
    // Leo, take android_os_BinderInternal_handleGc Methods and com.android.internal.os.BinderInternal.handleGc Method to bind
    { "handleGc", "()V", (void*)android_os_BinderInternal_handleGc }
};
 
const char* const kBinderInternalPathName = "com/android/internal/os/BinderInternal";
 
static int int_register_android_os_BinderInternal(JNIEnv* env)
{
    jclass clazz = FindClassOrDie(env, kBinderInternalPathName);
 
    // Leo, gBinderInternalOffsets.mClass The assignment is BinderInternal.java file
    gBinderInternalOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
    gBinderInternalOffsets.mForceGc = GetStaticMethodIDOrDie(env, clazz, "forceBinderGc", "()V");
 
    // Leo, register JNI function
    return RegisterMethodsOrDie(
        env, kBinderInternalPathName,
        gBinderInternalMethods, NELEM(gBinderInternalMethods));
}
static struct binderinternal_offsets_t
{
    // Class state.
    jclass mClass;
    jmethodID mForceGc;
 
} gBinderInternalOffsets;
gBinderInternalOffsets.mClass and Java World com.android.internal.os.BinderInternal class

gBinderInternalOffsets.mForceGc and com.android.internal.os.BinderInternal Class forceBinderGc Methods corresponding to the

And will gBinderInternalMethods The corresponding Java The way of the world and C The world correspondence method corresponds one by one

2). BinderProxy

static const JNINativeMethod gBinderProxyMethods[] = {
     /* name, signature, funcPtr */
    {"pingBinder",          "()Z", (void*)android_os_BinderProxy_pingBinder},
    {"isBinderAlive",       "()Z", (void*)android_os_BinderProxy_isBinderAlive},
    {"getInterfaceDescriptor", "()Ljava/lang/String;", (void*)android_os_BinderProxy_getInterfaceDescriptor},
    {"transactNative",      "(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z", (void*)android_os_BinderProxy_transact},
    {"linkToDeath",         "(Landroid/os/IBinder$DeathRecipient;I)V", (void*)android_os_BinderProxy_linkToDeath},
    {"unlinkToDeath",       "(Landroid/os/IBinder$DeathRecipient;I)Z", (void*)android_os_BinderProxy_unlinkToDeath},
    {"destroy",             "()V", (void*)android_os_BinderProxy_destroy},
};
 
const char* const kBinderProxyPathName = "android/os/BinderProxy";
 
static int int_register_android_os_BinderProxy(JNIEnv* env)
{
    jclass clazz = FindClassOrDie(env, "java/lang/Error");
    gErrorOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
 
    clazz = FindClassOrDie(env, kBinderProxyPathName);
    gBinderProxyOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
    gBinderProxyOffsets.mConstructor = GetMethodIDOrDie(env, clazz, "<init>", "()V");
    gBinderProxyOffsets.mSendDeathNotice = GetStaticMethodIDOrDie(env, clazz, "sendDeathNotice",
            "(Landroid/os/IBinder$DeathRecipient;)V");
 
    gBinderProxyOffsets.mObject = GetFieldIDOrDie(env, clazz, "mObject", "J");
    gBinderProxyOffsets.mSelf = GetFieldIDOrDie(env, clazz, "mSelf",
                                                "Ljava/lang/ref/WeakReference;");
    gBinderProxyOffsets.mOrgue = GetFieldIDOrDie(env, clazz, "mOrgue", "J");
 
    clazz = FindClassOrDie(env, "java/lang/Class");
    gClassOffsets.mGetName = GetMethodIDOrDie(env, clazz, "getName", "()Ljava/lang/String;");
 
    return RegisterMethodsOrDie(
        env, kBinderProxyPathName,
        gBinderProxyMethods, NELEM(gBinderProxyMethods));
}
static struct binderproxy_offsets_t
{
    // Class state.
    jclass mClass;
    jmethodID mConstructor;
    jmethodID mSendDeathNotice;
 
    // Object state.
    jfieldID mObject;
    jfieldID mSelf;
    jfieldID mOrgue;
 
} gBinderProxyOffsets;
gBinderProxyOffsets.mClass and Java World android.os.BinderProxy class

gBinderProxyOffsets.mConstructor and android.os.BinderProxy Class init Methods corresponding to the

gBinderProxyOffsets.mSendDeathNotice and android.os.BinderProxy Class sendDeathNotice Methods corresponding to the

gBinderProxyOffsets.mSelf and android.os.BinderProxy Class mSelf Object correspondence
gBinderProxyOffsets.mObject and android.os.BinderProxy Class mObject Object correspondence
And will gBinderProxyMethods The corresponding Java The way of the world and C The world correspondence method corresponds one by one

2. BinderInternal.getContextObject Function analysis

BinderInternal.java

/**
     * Return the global "context object" of the system.  This is usually
     * an implementation of IServiceManager, which you can use to find
     * other services.
     */
    public static final native IBinder getContextObject();
It's called native Layer of getContextObject Method , Remember the previous Binder Of JNI In registration , Registered BinderInternal Methods? ?
static const JNINativeMethod gBinderInternalMethods[] = {
     /* name, signature, funcPtr */
    // Leo, take android_os_BinderInternal_getContextObject Methods and com.android.internal.os.BinderInternal.getContextObject Method to bind
    { "getContextObject", "()Landroid/os/IBinder;", (void*)android_os_BinderInternal_getContextObject },
    // Leo, take android_os_BinderInternal_joinThreadPool Methods and com.android.internal.os.BinderInternal.joinThreadPool Method to bind
    { "joinThreadPool", "()V", (void*)android_os_BinderInternal_joinThreadPool },
    // Leo, take android_os_BinderInternal_disableBackgroundScheduling Methods and com.android.internal.os.BinderInternal.disableBackgroundScheduling Method to bind
    { "disableBackgroundScheduling", "(Z)V", (void*)android_os_BinderInternal_disableBackgroundScheduling },
    // Leo, take android_os_BinderInternal_setMaxThreads Methods and com.android.internal.os.BinderInternal.setMaxThreads Method to bind
    { "setMaxThreads", "(I)V", (void*)android_os_BinderInternal_setMaxThreads },
    // Leo, take android_os_BinderInternal_handleGc Methods and com.android.internal.os.BinderInternal.handleGc Method to bind
    { "handleGc", "()V", (void*)android_os_BinderInternal_handleGc }
};
getContextObject and android_util_Binder.cpp In the document android_os_BinderInternal_getContextObject Methods corresponding to the
static jobject android_os_BinderInternal_getContextObject(JNIEnv* env, jobject clazz)
{
    // Leo, The return is new BpBinder(0)
    sp<IBinder> b = ProcessState::self()->getContextObject(NULL);
    // Leo, The method is JNI Application , The return is BinderProxy
    return javaObjectForIBinder(env, b);
}
Two methods are called here , So let's look at it one by one
3. ProcessState Of getContextObject Method

ProcessState.cpp

sp<ProcessState> ProcessState::self()
{
    Mutex::Autolock _l(gProcessMutex);
    if (gProcess != NULL) {
        return gProcess;
    }
    // Leo, initialization ProcessState object
    gProcess = new ProcessState;
    return gProcess;
}
OK, The singleton pattern , initialization ProcessState
ProcessState::ProcessState()
    : mDriverFD(open_driver()) // Leo, open binder equipment
    , mVMStart(MAP_FAILED)
    , mThreadCountLock(PTHREAD_MUTEX_INITIALIZER)
    , mThreadCountDecrement(PTHREAD_COND_INITIALIZER)
    , mExecutingThreadsCount(0)
    , mMaxThreads(DEFAULT_MAX_BINDER_THREADS)
    , mStarvationStartTimeMs(0)
    , mManagesContexts(false)
    , mBinderContextCheckFunc(NULL)
    , mBinderContextUserData(NULL)
    , mThreadPoolStarted(false)
    , mThreadPoolSeq(1)
{
    if (mDriverFD >= 0) {
        // mmap the binder, providing a chunk of virtual address space to receive transactions.
        // Leo, by binder Devices allocate address space
        mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
        if (mVMStart == MAP_FAILED) {
            // *sigh*
            ALOGE("Using /dev/binder failed: unable to mmap transaction memory.\n");
            close(mDriverFD);
            mDriverFD = -1;
        }
    }
 
    LOG_ALWAYS_FATAL_IF(mDriverFD < 0, "Binder driver could not be opened.  Terminating.");
}
ProcessState Initializing , Open the /dev/binder equipment , And allocate address space to the device
Next , Call its getContextObject Method

sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
{
    return getStrongProxyForHandle(0);
}
Next
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
    sp<IBinder> result;
 
    AutoMutex _l(mLock);
 
    handle_entry* e = lookupHandleLocked(handle);
 
    if (e != NULL) {
        ......
        IBinder* b = e->binder;
        if (b == NULL || !e->refs->attemptIncWeak(this)) {
            if (handle == 0) {
               ......
                Parcel data;
                status_t status = IPCThreadState::self()->transact(
                        0, IBinder::PING_TRANSACTION, data, NULL, 0);
                if (status == DEAD_OBJECT)
                   return NULL;
            }
 
            b = new BpBinder(handle); 
            e->binder = b;
            if (b) e->refs = b->getWeakRefs();
            result = b;
        } else {
            // This little bit of nastyness is to allow us to add a primary
            // reference to the remote proxy when this team doesn't have one
            // but another team is sending the handle to us.
            result.force_set(b);
            e->refs->decWeak(this);
        }
    }
 
    return result;
}
ProcessState::handle_entry* ProcessState::lookupHandleLocked(int32_t handle)
{
    const size_t N=mHandleToObject.size();
    if (N <= (size_t)handle) {
        handle_entry e;
        e.binder = NULL;
        e.refs = NULL;
        status_t err = mHandleToObject.insertAt(e, N, handle+1-N);
        if (err < NO_ERROR) return NULL;
    }
    return &mHandleToObject.editItemAt(handle);
}
From here on , First call lookupHandleLocked Method , Because this is the first call , So create a new handle_entry, And back to , Moreover, its binder and refs by NULL
that getStrongProxyForHandle Method and then go down , because binder by NULL,mHandle What's coming in is 0, So enter the judgment condition , Last new BpBinder, And the parameter is 0

therefore ,
sp<IBinder> b = ProcessState::self()->getContextObject(NULL);
The return is new BpBinder(0)
4. javaObjectForIBinder Method resolution

// Leo, val by new BpBinder(0)
jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val)
{
    // Leo, Not for NULL
    if (val == NULL) return NULL;
 
    /*
     * Leo, because BpBinder No inheritance Binder Of checkSubclass Method
     *       So the call is Binder.cpp Medium checkSubclass Method , return false
    */
    if (val->checkSubclass(&gBinderOffsets)) {
        // One of our own!
        jobject object = static_cast<JavaBBinder*>(val.get())->object();
        LOGDEATH("objectForBinder %p: it's our own %p!\n", val.get(), object);
        return object;
    }
 
    // For the rest of the function we will hold this lock, to serialize
    // looking/creation/destruction of Java proxies for native Binder proxies.
    AutoMutex _l(mProxyLock);
 
    // Someone else's...  do we know about it?
    // Leo, First time in , Obviously not
    jobject object = (jobject)val->findObject(&gBinderProxyOffsets);
    if (object != NULL) {
        jobject res = jniGetReferent(env, object);
        if (res != NULL) {
            ALOGV("objectForBinder %p: found existing %p!\n", val.get(), res);
            return res;
        }
        LOGDEATH("Proxy object %p of IBinder %p no longer in working set!!!", object, val.get());
        android_atomic_dec(&gNumProxyRefs);
        val->detachObject(&gBinderProxyOffsets);
        env->DeleteGlobalRef(object);
    }
 
    // Leo, gBinderProxyOffsets.mClass = android/os/BinderProxy
    object = env->NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor);
    if (object != NULL) {
        LOGDEATH("objectForBinder %p: created new proxy %p !\n", val.get(), object);
        // The proxy holds a reference to the native object.
        // Leo, gBinderProxyOffsets.mObject The assignment is new BpBinder(0)
        env->SetLongField(object, gBinderProxyOffsets.mObject, (jlong)val.get());
        val->incStrong((void*)javaObjectForIBinder);
 
        // The native object needs to hold a weak reference back to the
        // proxy, so we can retrieve the same proxy if it is still active.
        jobject refObject = env->NewGlobalRef(
                env->GetObjectField(object, gBinderProxyOffsets.mSelf));
        val->attachObject(&gBinderProxyOffsets, refObject,
                jnienv_to_javavm(env), proxy_cleanup);
 
        // Also remember the death recipients registered on this proxy
        sp<DeathRecipientList> drl = new DeathRecipientList;
        drl->incStrong((void*)javaObjectForIBinder);
        env->SetLongField(object, gBinderProxyOffsets.mOrgue, reinterpret_cast<jlong>(drl.get()));
 
        // Note that a new object reference has been created.
        android_atomic_inc(&gNumProxyRefs);
        incRefsCreated(env);
    }
 
    return object;
}
Incoming parameter , We just analyzed , The second parameter is new BpBinder(0), and BpBinder Without inheriting a parent class checkSubclass Method , So the method of its parent class is called , return false
and jobject object = (jobject)val->findObject(&gBinderProxyOffsets); for the first time , Obviously NULL, therefore , Then down

gBinderProxyOffsets.mClass, This , We had an analysis before Binder Of JNI register , Confirm that the value is android.os.BinderProxy

gBinderProxyOffsets.mConstructor, How to construct it

therefore , The statement returns Java The object of the layer BinderProxy

Next ,

env->SetLongField(object, gBinderProxyOffsets.mObject, (jlong)val.get());
take new BpBinder(0) Assign a value to gBinderProxyOffsets.mObject
thus , Whole BinderInternal.getContextObject The process of , Analysis here , It's clear , Initialize and return BinderProxy object , And will BinderInternal Of mObject The object is assigned the value new BpBinder(0)

版权声明
本文为[Tianwang gaidihu 626]所创,转载请带上原文链接,感谢