现在要搞明白JAVA层app调用跨进程的Service接口时,它的binder是怎样从Java->jni-->native--->binder驱动的这条链路:就是上图中的左半部分从上至下的流程。所以切入点在于,如app调用另一个进程的Service接口的getString()进行分析,如下:
myService.getString(); //调用服务接口
-->进入aidl的getString():即IMyAidlInterface.Stub.Proxy.getString()
-->mRemote.transact();
-->IBinder.java->transact();
-->BinderProxy.java->transact(); //还有一个是Binder.java那个是服务端的,所以这边要看BinderProxy客户端这边
-->transactNative(code, data, reply, flags); //感觉到头了没路了,进入了JNI层(Zygote启动->JNI的注册,在那里面)
先来看看ZygoteInit.java做什么事。
app_main.cpp: //启动zygote
-->runtime.start("...ZygoteInit", args,zygote);
-->startReg() //注册JNI
-->register_jni_procs(gRegJNI,...); //注册了很多jNI接口
来看看gRegJNI[]={
...
REG_JNI(register_android_os_Binder), //在这边注册,就是前面的
-->android_util_Binder.cpp->int_register_android_os_BinderProxy():
-->gBinderProxyMethods[]={
//对应上面的transactNative的本地接口。
{"transactNaive", "(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z",(void*)android_os_BinderProxy_transact}
}
...
}
所以,前面调用到transactNative之后,就进入到JNI层的android_util_Binder.cpp中的
android_os_BinderProxy_transact(.., jObject obj)处理。
-->这个obj是Binder Proxy.
//将java的数据转成C++层的对象
Parcel* data = parcelForJavaObject(env, dataObj);
Parcel* reply = parcelForJavaObject(env, replyObj);
//重要:调用getBPNativeData函数获得BinderProxy在Native中对应的BinderProxyNativeData
//target本质上就是Native的BpBinder.
IBinder *target = getBPNativeData(env, obj)->mObject.get();
//下面这个语句就是反射。
-->return (BinderProxyNativeData*)env->GetLongField(obj, gBinderProxyOffset.mNative);
target->transact(code, *data, replay, flags);//这个直接进入了BpBinder.cpp的代码
即: BpBinder.cpp->transact()
//进入调用下面:创建并维持一个线程单例并调用transact接口
-->IPCThreadState::self()->transact(mHandle, code, data, reply, flags);
-->IPCThreadState.cpp->WaitForResponse();
talkWithDriver();
-->bwr.write_buffer = mOut.data();//设置缓存
ioctl(FD, BINDER_WRITE_READ, &bwr); //读写驱动
-->case BR_REPLY:
-->mIn.Read();
上面就是整体的调用流程,非常的清晰明了。