该小节我们讲解Binder系统使用java实现Server端的机制,下面是指向讲解的binder系统的分成图示:
在这幅图中有3个疑问:
1.java的client端怎么发送数据给驱动程序,驱动只能和C或者C++代码对接。
2.Server端怎么从驱动程序读取数据。
3.Server端读取到数据之后,其如何调用到IHelloService.cpp中的onTransact方法。
在上小节中,我们已经解决了第一个问题,该小节我们讲解第二个和第三个问题。
首先我们来看看问题二
Server如何读取数据
首先我们看看TestServer.java:
public static void main(String args[])
while (true)
可以看到,其一直都在while循环,并且基本没有做 任何事情,那么他是怎么读取数据的呢?
之前我们执行TestServer程序的时候是使用:
CLASSPATH=./TestServer.jar app_process ./ TestServer &
现在我们查看一下app_process命令的源码,我们打开app_main.cpp:
int main(int argc, char* const argv[])
virtual void onStarted()
/*创建一个子线程*/
proc->startThreadPool();
/*调用TestServer.java中的main函数,启动程序*/
ar->callMain(mClassName, mClass, mArgs);
spawnPooledThread(true);
t->run(name.string());
/*执行threadLoop函数*/
sp<Thread> t = new PoolThread(isMain);
/*线程调用joinThreadPool函数,其内部为一个do-while循环*/
IPCThreadState::self()->joinThreadPool(mIsMain);
可以看到起进入到joinThreadPool函数,循环读取数据。读取到的数据中含有.ptr/.cookie,他会把cookie转化为一个BBbinder对象,然后调用他的transact函数。
void IPCThreadState::joinThreadPool(bool isMain)
{
do {
result = getAndExecuteCommand();
/*读取到数据*/
result = talkWithDriver();
/*分析数据*/
result = executeCommand(cmd)
case BR_TRANSACTION:
/*可以看到起把tr.cookie转化为一个Binder对象,调用其中的transact函数*/
error = reinterpret_cast<Binder*>(tr.cookie)->transact(tr.code, buffer,&reply, tr.flags);
} while (result != -ECONNREFUSED && result != -EBADF);
}
现在我们看看cookie是怎么设置的?他是通过addsevice进行设置的,打开TestServer.cpp:
ServiceManager.addService("hello", new HelloService());
我们可以看到:
- new HelloService()为一个java对象。
- 处理数据时把.cookie转化为一个BBbinder对象,他是C++的对象。
所以:addService中肯定会把JAVA对象转化为一个BBbinder派生对象,存在.cookie中。
下面我们围绕上述2点查看源码,在这之前,先看下结论:
1.addService会通过JNI调用某个C++函数。
创建一个BBinder派生类对象JavaBBinder对象。
他的.mOject指向JAVA对象: new HelloService()
他含有onTransacet函数
把这个对象存入到.cookie(最终存入到binder驱动中该服务对应的binder_node.cookie)
2.Service进程从驱动中读到数据,里面含有cookie值,
把他转化为BBinder对象,
调用他的transact
他会调用到派生类JavaBBinder中定义的onTransacet函数
3.JavaBBinder中定义的onTransacet函数(C++)
调用IHelloService中定义的onTransacet函数(java)
4.IHelloService中定义的onTransacet函数(java)
分析数据
调用sayhello/sayhello_to
下面我开始阅读源码:
根据:
ServiceManager.addService("hello", new HelloService());
上小节我们分析过ServiceManager.addService,其最终会调用到ServiceManagerProxy.addService。
我们进入ServiceManagerNative.java找到ServiceManagerProxy类中的addService:
public void addService(String name, IBinder service, boolean allowIsolated)
/*parcel.java中实现*/
data.writeStrongBinder(service);
/*最终调用一个C++函数*/
/*val = service = new HelloService()*/
/*对应android_os_Parcel_writeStrongBinder(c++)*/
nativeWriteStrongBinder(mNativePtr, val);
下面我们分析一下android_os_Parcel_writeStrongBinder:
/*它会构造一个JavaBBinder对象(c++),.mObject=new HelloService() JAVA对象,然后让.cookie=JavaBBinder对象(c++)*/
static void android_os_Parcel_writeStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr, jobject object)
/*把java的Parcel转化为C++ Parcel*/
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
/*.cookie = ibinderForJavaObject(env, object)得到一个JavaBBinder对象*/
parcel->writeStrongBinder(ibinderForJavaObject(env, object));
我们分析一下ibinderForJavaObject(env, object):
/*把一个Java对象(new HelloService())转换为c++ IBinder对象:object = new HelloService() */
sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj)
JavaBBinderHolder* jbh = (JavaBBinderHolder*)env->GetLongField(obj, gBinderOffsets.mObject);
return jbh != NULL ? jbh->get(env, obj) : NULL;
/*看看其jbh->get(env, obj)函数*/
b = new JavaBBinder(env, obj);//object = new HelloService()
在JavaBBinder中存在成员mObject = object = new HelloService()
下面我们分析其怎么从驱动获得.cookie,他是一个JAVABBinder对象,调用他的transact函数,到最后导致JAVABBinder对象的onTransact函数被调用,找到android_util_Binder.cpp中JAVABBinder类中的函数:
/*(调用java里的某个函数)*/
virtual status_t onTransact(
// mObject指向 HelloService对象
// gBinderOffsets.mExecTransact指向: java Binder类中的execTransact方法
// 调用HelloService(派生自Binder)对象中的execTransact方法
jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact,code, reinterpret_cast<jlong>(&data), reinterpret_cast<jlong>(reply), flags);
execTransact方法在Binder.java中实现:
private boolean execTransact(int code, long dataObj, long replyObj,int flags)
/*调用HelloService中的onTransact方法(来自IHelloService.Stube)*/
onTransact(code, data, reply, flags);
为了大家方便,下面是一个总结的截图: