This article was first published on the wechat public account “Backend Technical Officer”

Associated series Android AOSP Basic series Android system startup series Application process startup series Android In-depth understanding of the four major components of Android Context series Android in-depth understanding of JNI series WMS series AMS series Android package management mechanism series Android input system series

For more information, check out my independent blog’s body of knowledge: liuwangshu.cn/system/

Java Binder Initialization

preface

In this article, Binder mechanism is divided into three layers according to the layers of Android system:

  1. Java Binder (Binder for Framework layer)
  2. Native Binder(Corresponding to Native layer)
  3. Kernel Binder(Corresponding to the Kernel layer Binder)

In previous articles, I have been introducing Native binders and Kernel Binders. Their architectures are summarized in the following figure.

Binder is a proxy class for the interaction between the Client and Server, and BBinder represents the Server, so the figure above can be changed to:

Android Binder principles (4) ServiceManager startup process

1. JNI registration for Java Binder

Java Binders need to communicate with Native Binders through JNI, which is registered during Zygote process startup. The code is shown below. frameworks/base/core/jni/AndroidRuntime.cpp

void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
    ...
    JniInvocation jni_invocation;
    jni_invocation.Init(NULL);
    JNIEnv* env;
    if(startVm(&mJavaVM, &env, zygote) ! =0) {/ / 1
        return;
    }
    onVmCreated(env);
    if (startReg(env) < 0) {
        ALOGE("Unable to register all android natives\n");
        return; }... }Copy the code

The Zygote start function is used to start a Java vm. The Zygote start function is used to start a Java VM. The Zygote start function is used to start a Java VM. The startReg function is shown below. frameworks/base/core/jni/AndroidRuntime.cpp

/*static*/ int AndroidRuntime::startReg(JNIEnv* env)
{
    ATRACE_NAME("RegisterAndroidNatives");
    androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);

    ALOGV("--- registering native functions ---\n");
    env->PushLocalFrame(200);

    if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {/ / 1
        env->PopLocalFrame(NULL);
        return - 1;
    }
    env->PopLocalFrame(NULL);
    return 0;
}
Copy the code

The register_jni_procs function at comment 1 loops through the methods corresponding to the members of the gRegJNI array, as shown below.

static int register_jni_procs(const RegJNIRec array[].size_t count, JNIEnv* env)
{
    for (size_t i = 0; i < count; i++) {
        if (array[i].mProc(env) < 0) {
#ifndef NDEBUG
            ALOGD("-- -- -- -- -- -- -- -- -- --!!! %s failed to load\n".array[i].mName);
#endif
            return - 1; }}return 0;
}
Copy the code

There are more than 100 member variables in the gRegJNI array:

static const RegJNIRec gRegJNI[] = {
    REG_JNI(register_com_android_internal_os_RuntimeInit),
    REG_JNI(register_com_android_internal_os_ZygoteInit_nativeZygoteInit),
    REG_JNI(register_android_os_SystemClock),
    ...
    REG_JNI(register_android_os_Binder),/ / 1. };Copy the code

Where REG_JNI is a macro definition:

    #define REG_JNI(name) { name }
    struct RegJNIRec {
        int (*mProc)(JNIEnv*);
    };
Copy the code

It is actually calling the function that corresponds to the parameter name. The function responsible for communication between Java Binder and Native Binder is register_android_os_Binder at note 1, with the code shown below. frameworks/base/core/jni/android_util_Binder.cpp

int register_android_os_Binder(JNIEnv* env)
{   
    // Register the Binder class
    if (int_register_android_os_Binder(env) < 0)
        return - 1;
    // Register the BinderInternal class
    if (int_register_android_os_BinderInternal(env) < 0)
        return - 1;
    // Register the BinderProxy class
    if (int_register_android_os_BinderProxy(env) < 0)
        return - 1; .return 0;
}
Copy the code

The register_android_os_Binder function does three things: 1. Register with Binder 2. Register with BinderInternal 3. Registered BinderProxy class

They are a small subset of Java Binder associated classes, and their relationships are shown below.

  • The IBinder interface defines many variables of integer type, one of which is calledFLAG_ONEWAYInteger variable of. When a client makes a call, the client typically blocks until the server returns the result. Set up theFLAG_ONEWAYAfter that, the client only needs to send the request to the server and can immediately return without waiting for the result of the server, which is a non-blocking method.
  • Binder and BinderProxy implement the IBinder interface, Binder representing the server and BinderProxy representing the client.
  • BinderInternal is only used within the Binder framework, and its inner class GcWatcher is used for processing and Binder garbage collection.
  • A Parcel is a data wrapper that can be delivered between processes. A Parcel can deliver both basic data types and Binder objects. Binder communication uses a Parcel for client-server data interaction. A Parcel is implemented in both Java and Native parts, in the Native part.

Binder and BinderInternal class registrations are analyzed below.

1.1 Registration of Binder classes

To register the Binder class, call the int_register_android_os_Binder function as shown below. frameworks/base/core/jni/android_util_Binder.cpp

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 },
    { "getNativeBBinderHolder"."()J", (void*)android_os_Binder_getNativeBBinderHolder },
    { "getNativeFinalizer"."()J", (void*)android_os_Binder_getNativeFinalizer },
    { "blockUntilThreadAvailable"."()V", (void*)android_os_Binder_blockUntilThreadAvailable }
};
const char* const kBinderPathName = "android/os/Binder";/ / 1
static int int_register_android_os_Binder(JNIEnv* env)
{
    jclass clazz = FindClassOrDie(env, kBinderPathName);/ / 2

    gBinderOffsets.mClass = MakeGlobalRefOrDie(env, clazz);/ / 3
    gBinderOffsets.mExecTransact = GetMethodIDOrDie(env, clazz, "execTransact"."(IJJI)Z");/ / 4
    gBinderOffsets.mObject = GetFieldIDOrDie(env, clazz, "mObject"."J");

    return RegisterMethodsOrDie(
        env, kBinderPathName,
        gBinderMethods, NELEM(gBinderMethods));
}
Copy the code

The value of kBinderPathName at note 1 is “Android/OS /Binder”, which is the full pathname of Binder in Java Binder. Binder’s Class object is obtained from this pathname and assigned to clazz of type JClass, Binder’s JNI proxy for Java layer. In comment 3, the local reference clazz is converted to a global reference and assigned to gbinderOffsets.mclass using the MakeGlobalRefOrDie function. Comment 4 place is used to find the Java layer of Binder execTransact and assigned to the members of gBinderOffsets. MExecTransact. Note 5 is used to find the Java layer’s Binder member variable mObject and assign it to gbinderoffsets.mobject. The last line registers the function defined in gBinderMethods through the RegisterMethodsOrDie function, where gBinderMethods is an array of type JNINativeMethod, Binder Native methods (Java layer) correspond to JNI layer functions.

GBinderMethods are defined as follows.

static struct bindernative_offsets_t
{
    jclass mClass;
    jmethodID mExecTransact;
    jfieldID mObject;

} gBinderOffsets;
Copy the code

There are two reasons to use gBinderMethods to hold variables and methods: 1. For the sake of efficiency, it is obviously inefficient to query methods and variables every time a related method is called. 2. These member variables and methods are local references. These local references are automatically released when int int_register_android_os_Binder returns, so use gBinderOffsets to save them for later use.

For those unfamiliar with JNI, see Android for an in-depth understanding of JNI (2) type conversions, method signatures, and JNIEnv.

1.2 Registration of BinderInternal classes

Call int_register_android_os_BinderInternal to register the BinderInternal class, as shown below. frameworks/base/core/jni/android_util_Binder.cpp

const char* const kBinderInternalPathName = "com/android/internal/os/BinderInternal";
static int int_register_android_os_BinderInternal(JNIEnv* env)
{
    jclass clazz = FindClassOrDie(env, kBinderInternalPathName);

    gBinderInternalOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
    gBinderInternalOffsets.mForceGc = GetStaticMethodIDOrDie(env, clazz, "forceBinderGc"."()V");
    gBinderInternalOffsets.mProxyLimitCallback = GetStaticMethodIDOrDie(env, clazz, "binderProxyLimitCallbackFromNative"."(I)V");

    jclass SparseIntArrayClass = FindClassOrDie(env, "android/util/SparseIntArray");
    gSparseIntArrayOffsets.classObject = MakeGlobalRefOrDie(env, SparseIntArrayClass);
    gSparseIntArrayOffsets.constructor = GetMethodIDOrDie(env, gSparseIntArrayOffsets.classObject,
                                                           "<init>"."()V");
    gSparseIntArrayOffsets.put = GetMethodIDOrDie(env, gSparseIntArrayOffsets.classObject, "put"."(II)V");

    BpBinder::setLimitCallback(android_os_BinderInternal_proxyLimitcallback);

    return RegisterMethodsOrDie(
        env, kBinderInternalPathName,
        gBinderInternalMethods, NELEM(gBinderInternalMethods));
}
Copy the code

Similar to the implementation of int_register_android_os_Binder, three main things are done: 1. Get Clazz, BinderInternal’s representative at the JNI layer. 2. Store useful member variables and methods from the BinderInternal class into gBinderInternalOffsets. 3. Register JNI functions corresponding to Native methods of the BinderInternal class.

Binder, BinderInternal, BinderProxy, BinderProxy, BinderProxy, BinderProxy, BinderProxy, BinderProxy, BinderProxy


Share Java, Python, big data, algorithms, big front-end, AI-related technologies, focus on programmers’ technical improvement and career promotion, help 10W+ programmers to become technical officers and architects!