PARCEL in Binder Communication ReadstrongBinder and Writestrongbinder

In Binder IPC communication, Binder is the communication medium, and Parcel is the content of the communication. In the process of remote call, the parameters are packaged in the form of Parcel to pass.

On the Proxy side of IPC communication, we can often see the following similar code, some parameters will be packaged in Parcel. Look at the data and reply below.

public void< span style="color: #000000;"> publishService(IBinder token,

Intent intent, IBinder service) throws RemoteException {
Parcel data
= Parcel.obtain();
Parcel reply
= Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(token);
intent.writeToParcel(data,
0);
data.writeStrongBinder(service);
mRemote.transact(PUBLISH_SERVICE_TRANSACTION, data, reply,
0);
reply.readException();
data.recycle();
reply.recycle();
}

In IPC communication, android writes IBinder to Parcel through the member function of the Parcel class writeStrongBinder(), and then Send out via mRemote.

2.writeStrongBinder()

Next, let’s take a look at what is done in the writeStrongBinder() function.
/frameworks/base/core/java/android/os/Parcel.java

public final class Parcel {


/**
* Write an object into the parcel at the current dataPosition(),
* growing dataCapacity() if needed.
*/
public final void writeStrongBinder(IBinder val) {
nativeWriteStrongBinder(mNativePtr, val);
}
private static native void nativeWriteStrongBinder(int nativePtr, IBinder val);

}

Look, the native method is called again here, we will find that some Parcels in the Java layer are actually just a package of the C/C++ layer, most The operation still relies on JNI to call Native operations.
Look at the corresponding method in C++:

/frameworks/base/core/jni/android_os_Parcel.cpp

static void android_os_Parcel_writeStrongBinder(JNIEnv* env, jclass clazz , jint nativePtr, jobject object)

{
Parcel
* parcel = reinterpret_cast(nativePtr);
if (parcel != NULL) {
const status_t err = parcel->writeStrongBinder(ibinderForJavaObject(env, object ));
if (err != NO_ERROR) {
signalExceptionForError(env, clazz, err);
}
}
}

The most important thing is ibinderForJavaObject This function, continue to track the code:

/frameworks/base/core/jni/android_util_Binder.cpp

sp ibinderForJavaObject (JNIEnv* env, jobject obj)

{
if (obj == NULL) return NULL;

if (env->IsInstanceOf(obj, gBinderOffsets.mClass)) {//mClass points to the Binder class in the Java layer
JavaBBinderHolder* jbh = (JavaBBinderHolder*)
env
->GetIntField(obj, gBinderOffsets.mObject);
return jbh != NULL? jbh->get(env, obj): NULL; //get() returns a JavaBBinder, inherited from BBinder
}

if (env->IsInstanceOf(obj, gBinderProxyOffsets.mClass)) {//mClass points to the BinderProxy class of the Java layer
return (IBinder*)
env
->GetIntField(obj, gBinderProxyOffsets.mObject); // Return a BpBinder, mObject is its address value
}
ALOGW(
"ibinderForJavaObject: %p is not a Binder object", obj);
return NULL;
}

This function is to find the corresponding C++ object according to the passed in Java object. The parameter obj here may point to two types of objects: Binder Object or BinderProxy object. We actually encountered these two objects in the RemoteService article. The Binder object is the mRemoteBinder implemented in the Service, and the BinderProxy object is the service passed in by the callback in the Activity.

Next, if the Binder object is passed in, then gBinderOffsets.mObject will be converted to JavaBBinderHolder, and a JavaBBinder object will be obtained from it. JavaBBinder inherits from BBinder. (In the RemoteService article, Service will pass mRemoteBinder to AMS in the onBind callback, here is the Binder object)

If the BinderProxy object is passed in. A BpBinder will be returned, and the address value of this BpBinder will be stored in gBinderProxyOffsets.mObject. (In the RemoteService article, what AMS will pass to Acticity is the BinderProxy object).

At this point, you may be wondering, why does Service pass the Binder object to AMS, but later AMS passes the BinderProxy object to Activity? We will talk about this later, (it can be said first, in fact, because these Binder objects will be transmitted through the bottom layer, then during the transmission process, the Binder module will transform these objects according to different situations)

3.readStrongBinder()

It is also a JNI call:

/frameworks/base/core/jni/android_os_Parcel.cpp

static jobject android_os_Parcel_readStrongBinder(JNIEnv* env, jclass clazz, jint nativePtr)

{
...
return javaObjectForIBinder(env, parcel->readStrongBinder());
}

/frameworks/base/core/jni/android_util_Binder.cpp
jobject javaObjectForIBinder(JNIEnv* env, const sp& val ) (1)

{
if (val == NULL) return NULL;
if (val->checkSubclass(&gBinderOffsets)) {(2)12 // One of our own!
jobject object = static_cast(val.get())->object();
LOGDEATH(
"objectForBinder %p: it‘s our own %p! ", val.get(), object);
return object;
}
...
jobject object
= (jobject)val->findObject(&gBinderProxyOffsets);
if (object != NULL) {
jobject res
= env->CallObjectMethod(object, gWeakReferenceOffsets.mGet); (3)
if (res != NULL) {
ALOGV(
"objectForBinder %p: found existing %p! ", val.get(), res);
return res;
}
...
}
object
= env->NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor); (4)
if (object != NULL) {
….
}
return object;
}

(1): The val here is similar to writeStrongBinder, but on the other hand, it may point to JavaBBinder or BpBinder .

(2): If it is JavaBBinder, it will return a Java object through the member function object(), which is the Binder object of the Java layer.

(3): If it is BpBinder, first find out whether there is already a BinderProxy object that needs to be used, and return a reference if found

(4): If no available reference is found, a new BinderProxy object is used.

public void publishService(IBinder token,

Intent intent, IBinder service)
throws RemoteException {
Parcel data
= Parcel.obtain();
Parcel reply
= Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(token);
intent.writeToParcel(data,
0);
data.writeStrongBinder(service);
mRemote.transact(PUBLISH_SERVICE_TRANSACTION, data, reply,
0);
reply.readException();
data.recycle();
reply.recycle();
}

public final class Parcel {


/**
* Write an object into the parcel at the current dataPosition(),
* growing dataCapacity() if needed.
*/
public final void writeStrongBinder(IBinder val) {
nativeWriteStrongBinder(mNativePtr, val);
}
private static native void nativeWriteStrongBinder(int nativePtr, IBinder val);

}

static void android_os_Parcel_writeStrongBinder(JNIEnv* env, jclass clazz, jint nativePtr, jobject object)

{
Parcel
* parcel = reinterpret_cast(nativePtr);
if (parcel != NULL) {
const status_t err = parcel->writeStrongBinder(ibinderForJavaObject(env, object ));
if (err != NO_ERROR) {
signalExceptionForError(env, clazz, err);
}
}
}

sp ibinderForJavaObject(JNIEnv* env, jobject obj)

{
if (obj == NULL) return NULL;

if (env->IsInstanceOf(obj, gBinderOffsets.mClass)) {//mClass points to the Binder class in the Java layer
JavaBBinderHolder* jbh = (JavaBBinderHolder*)
env
->GetIntField(obj, gBinderOffsets.mObject);
return jbh != NULL? jbh->get(env, obj): NULL; //get() returns a JavaBBinder, inherited from BBinder
}

if (env->IsInstanceOf(obj, gBinderProxyOffsets.mClass)) {//mClass points to the BinderProxy class of the Java layer
return (IBinder*)
env
->GetIntField(obj, gBinderProxyOffsets.mObject); // Return a BpBinder, mObject is its address value
}
ALOGW(
"ibinderForJavaObject: %p is not a Binder object", obj);
return NULL;
}

static jobject android_os_Parcel_readStrongBinder(JNIEnv* env, jclass clazz, jint nativePtr)

{
...
return javaObjectForIBinder(env, parcel->readStrongBinder());
}

jobject javaObjectForIBinder(JNIEnv* env, const sp& val) (1)

{
if (val == NULL) return NULL;
if (val->checkSubclass(&gBinderOffsets)) {(2)12 // One of our own!
jobject object = static_cast(val.get())->object();
LOGDEATH(
"objectForBinder %p: it‘s our own %p! ", val.get(), object);
return object;
}
...
jobject object
= (jobject)val->findObject(&gBinderProxyOffsets);
if (object != NULL) {
jobject res
= env->CallObjectMethod(object, gWeakReferenceOffsets.mGet); (3)
if (res != NULL) {
ALOGV(
"objectForBinder %p: found existing %p! ", val.get(), res);
return res;
}
...
}
object
= env->NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor); (4)
if (object != NULL) {
….
}
return object;
}

Leave a Comment

Your email address will not be published.