Android java layer binder parsing 1

Looking directly at ServiceManager's addService below

ServiceManager.java

public static void addService(String name, IBinder service) {
    try {
        getIServiceManager().addService(name, service, false);
    } catch (RemoteException e) {
        Log.e(TAG, "error in addService", e);
    }
}
private static IServiceManager getIServiceManager() {
    if (sServiceManager != null) {
        return sServiceManager;
    }

    // Find the service manager
    sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
    return sServiceManager;
}

1. BinderInternal.getContextObject()

BinderInternal.java

public static final native IBinder getContextObject();

The corresponding is a native method

android_util_Binder.cpp

 static jobject android_os_BinderInternal_getContextObject(JNIEnv* env, jobject clazz)
{
    sp<IBinder> b = ProcessState::self()->getContextObject(NULL);
    return javaObjectForIBinder(env, b);
}

Through articles ServiceManager Registration Service Resolution 1 for Android Binder ProcessState:: self()->getContextObject (NULL) gets a BpBinder object.

Here's a look at the javaObjectForIBinder method specifically.Is a native method implemented in android_Util_Binder.cppin

jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val)
{
    if (val == NULL) return NULL;

    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 of Java proxies for native Binder proxies.
    AutoMutex _l(mProxyLock);

    // Someone else's...  do we know about it?
    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);
    }
    // Create a BinderProxy object and register it with the ObjectManager object of the native BpBinder object
    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.
        // Save the BpBinder pointer of the native layer in the member field mObject of the BinderProxy object
        env->SetIntField(object, gBinderProxyOffsets.mObject, (int)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));
        // Register the newly created BinderProxy object with the ObjectManager object of BpBinder
        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->SetIntField(object, gBinderProxyOffsets.mOrgue, reinterpret_cast<jint>(drl.get()));

        // Note that a new object reference has been created.
        android_atomic_inc(&gNumProxyRefs);
        incRefsCreated(env);
    }

    return object;
}

The purpose of the javaObjectForIBinder method is to encapsulate the native layer's BpBinder object into a java layer's BpProxy object and return it to the java layer's caller.This implements the java layer's operation on the native layer binder.

The specific operations are as follows:
1. Create a java layer BinderProxy object
2. Associate BinderProxy with BpBinder objects in the native layer through JNI.

The one returned above is a BinderProxy object, so here's a look at the asInterface of ServiceManagerNative

2. ServiceManagerNative.asInterface(BinderInternal.getContextObject())

ServiceManagerNative.java

 static public IServiceManager asInterface(IBinder obj)
{
    if (obj == null) {
        return null;
    }
    IServiceManager in =
        (IServiceManager)obj.queryLocalInterface(descriptor);
    if (in != null) {
        return in;
    }

    return new ServiceManagerProxy(obj);
}

The obj object passed in above is a BinderProxy object, so look below at the queryLocalInterface method of BinderProxy.

Binder.java

final class BinderProxy implements IBinder {
    public IInterface queryLocalInterface(String descriptor) {
        return null;
    }
}

You can see that the return is null, so you end up returning new ServiceManagerProxy(obj)

public ServiceManagerProxy(IBinder remote) {
    mRemote = remote;
}

So mRemote corresponds to the BinderProxy object.

So what's actually called above is the addService method of the ServiceManagerProxy.

ServiceManagerNative$ServiceManagerProxy.java

 public void addService(String name, IBinder service, boolean allowIsolated)
        throws RemoteException {
    Parcel data = Parcel.obtain();
    Parcel reply = Parcel.obtain();
    data.writeInterfaceToken(IServiceManager.descriptor);
    data.writeString(name);
    data.writeStrongBinder(service);
    data.writeInt(allowIsolated ? 1 : 0);
    mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply, 0);
    reply.recycle();
    data.recycle();
}

Since mRemote corresponds to a BinderProxy object, here's a look at BinderProxy's transact method.

final class BinderProxy implements IBinder {
    public native boolean transact(int code, Parcel data, Parcel reply,
            int flags) throws RemoteException;
}

You can see that this is a native method.In android_Util_Binder.cppin

final class BinderProxy implements IBinder {
    public native boolean transact(int code, Parcel data, Parcel reply,
            int flags) throws RemoteException;
}

//You can see that this is a native method.In android_Util_Binder.cppin

static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
        jint code, jobject dataObj, jobject replyObj, jint flags) // throws RemoteException
{
    if (dataObj == NULL) {
        jniThrowNullPointerException(env, NULL);
        return JNI_FALSE;
    }
    // Converting a java layer Parcel object to a Native Parcel object
    Parcel* data = parcelForJavaObject(env, dataObj);
    if (data == NULL) {
        return JNI_FALSE;
    }
    // Converting a java layer Parcel object to a Native Parcel object
    Parcel* reply = parcelForJavaObject(env, replyObj);
    if (reply == NULL && replyObj != NULL) {
        return JNI_FALSE;
    }
    // Gets the Native Layer BpBinder object previously stored in the mObject field of BinderProxy
    IBinder* target = (IBinder*)
        env->GetIntField(obj, gBinderProxyOffsets.mObject);
    if (target == NULL) {
        jniThrowException(env, "java/lang/IllegalStateException", "Binder has been finalized!");
        return JNI_FALSE;
    }

    ALOGV("Java code calling transact on %p in Java object %p with code %d\n",
            target, obj, code);

#if ENABLE_BINDER_SAMPLE
    // Only log the binder call duration for things on the Java-level main thread.
    // But if we don't
    const bool time_binder_calls = should_time_binder_calls();

    int64_t start_millis;
    if (time_binder_calls) {
        start_millis = uptimeMillis();
    }
#endif
    //printf("Transact from Java code to %p sending: ", target); data->print();
    // Called through the BpBinder object in the Native layer, as described earlier
    status_t err = target->transact(code, *data, reply, flags);
    //if (reply) printf("Transact from Java code to %p received: ", target); reply->print();
#if ENABLE_BINDER_SAMPLE
    if (time_binder_calls) {
        conditionally_log_binder_call(start_millis, target, code);
    }
#endif

    if (err == NO_ERROR) {
        return JNI_TRUE;
    } else if (err == UNKNOWN_TRANSACTION) {
        return JNI_FALSE;
    }

    signalExceptionForError(env, obj, err, true /*canThrowRemoteException*/);
    return JNI_FALSE;
}

Tags: Java Android REST

Posted on Thu, 04 Jun 2020 14:36:44 -0400 by finalxerror