编程语言
首页 > 编程语言> > 05.Binder系统:第8课第6节_Binder系统_JAVA实现_内部机制_Server端

05.Binder系统:第8课第6节_Binder系统_JAVA实现_内部机制_Server端

作者:互联网

该小节我们讲解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());

我们可以看到:

  1. new HelloService()为一个java对象。
  2. 处理数据时把.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);

为了大家方便,下面是一个总结的截图:
在这里插入图片描述

标签:调用,java,05,对象,Binder,cookie,HelloService,new,JAVA
来源: https://blog.csdn.net/weixin_43013761/article/details/89227070