05.Binder系统:第7课第5节_Binder系统_c++实现_内部机制_数据传输

binder系统进程间的通信,其都是在驱动binder中实现的,也就是说,无论你的应用程序多么的复杂,最终还是通过ioctl这些标准的接口使用驱动程序,我们可以根据open,ioctl等等的调用过程分析C++程序的内部机制,和他的传输过程。

现在我们回顾一下应用程序是怎么和binder驱动打交道了,以test_server为例,他使用驱动程序的过程:
1.open:mmp
2.addservice:ioctl
3.while:read-data,parse-data,process data,reply:ioctl。

我们知道一个test_server进程可能是多线程的,如下图所示:
在这里插入图片描述
子线程是可以共享主线程的资源的,我们在主线程中使用open,然后代用mmap。基于c++面向对象的思想,即使调用mmap,其也是通过对象来完成的,打开源代码test_server.cpp,可以看到:

	/* 打开驱动, mmap */
	sp<ProcessState> proc(ProcessState::self());

其通过ProcessState进行mmap,注意ProcessState为一个单列模式,每个进程只有一个ProcessState对象,这个对象怎么创建呢?后面可以知道,其是通过ProcessState::self创建唯一的对象。

上图中的圈都代表循环,主线程循环以及子线程循环都是通过ioctl读取或者发送数据,同理,基于面向对象的实现,其循环过程,也由一个对象进行处理IPCThreadState,其同样是单列模式,每一个线程对应唯一的一个IPCThreadState对象。在上图中存在3个线程,这共有3个IPCThreadState对象。其通过IPCThreadState::self得到对象。

到这里,我们发现了两个类,分别为ProcessState与IPCThreadState,只要我们对着两个类进行详细的分析,我们就能掌握C++在binder系统中的数据传递过程。首先我们来看看ProcessState。

ProcessState

之前提到,open打开驱动的函数,是在ProcessState(ProcessState.cpp文件)执行的:

sp<ProcessState> ProcessState::self()
	gProcess = new ProcessState;

从上面我们可以知道,全局只有一个ProcessState对象。我们查看ProcessState的构造函数:

ProcessState::ProcessState()
    : mDriverFD(open_driver())
    , mVMStart(MAP_FAILED)
    , mThreadCountLock(PTHREAD_MUTEX_INITIALIZER)
    , mThreadCountDecrement(PTHREAD_COND_INITIALIZER)
    , mExecutingThreadsCount(0)
    ......
    // mmap the binder, providing a chunk of virtual address space to receive transactions.
    mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);

在上面我们可以看到mDriverFD(open_driver()),其不用多想,open的操作肯定是在其内部了:

static int open_driver()
	int fd = open("/dev/binder", O_RDWR | O_CLOEXEC);
	return fd;

可以知道最终fd赋值给了mDriverFD。从其中还能找到mmap函数。之前我们提到, 每个线程都存在一个IPCThreadState对象,其在调用ioctl时需要fd,可以知道IPCThreadState中肯定存在一个成员,其指向ProcessState中的mDriverFD。

现在我们查看IPCThreadState

IPCThreadState

打开test_server.cpp:

	/* 循环体 */
	ProcessState::self()->startThreadPool();//创建一个子线程
	IPCThreadState::self()->joinThreadPool();//主线程

我们先来看看IPCThreadState,他是如何为每个线程只创建一个对象(IPCThreadState.cpp):

IPCThreadState* IPCThreadState::self()
	IPCThreadState* st = (IPCThreadState*)pthread_getspecific(k);
	return new IPCThreadState;
	int key_create_value = pthread_key_create(&gTLS, threadDestructor)

在这里插讲一个知识点,线程特有数据(Thread specific Data)。如下图,main函数执行:
在这里插入图片描述
然后创建了3个线程,对每个线程创建一个IPCThreadState对象,意思是说,每个对象的他们之间是不一样的。他们存在于线程的局部空间之中,那么我们怎么实现这一点呢?

在Linux之中,pthread_key_create(),其创建一个key,既然有key那么肯定存在val。那么每个线程的val都不相同,可以调用pthread_setspecific对这个key设置一个键值。后续可以通过pthread_getspecific获得键值。

现在回过头查看return new IPCThreadState,其构造函数如下:

IPCThreadState::IPCThreadState()
    : mProcess(ProcessState::self()),
      mMyThreadId(gettid()),
      mStrictModePolicy(0),
      mLastTransactionBinderFlags(0)
{
	/*给每个线程设置一个唯一的键值,当后执行PCThreadState* st = (IPCThreadState*)pthread_getspecific(k);
	其键值不为空,则st不为空,会直接返回,不在执行new IPCThreadState创建新对象,这样就能保证每个线程只有一个IPCThreadState对象*/
    pthread_setspecific(gTLS, this);
    clearCaller();
    mIn.setDataCapacity(256);
    mOut.setDataCapacity(256);
}

常上面我们可以看到,其初始化列表中存在mProcess(ProcessState::self()),等价于mProcess=ProcessState::self()。通过前面我们知道每个ProcessState存在mDriverFD。下面我们回到test_server.cpp:

IPCThreadState::self()->joinThreadPool();

其为一个循环,这个循环所做的事情我们已经非常熟悉了,无非就是通过ioctl读写数据,然后把处理结构返回给test_client应用程序:

void IPCThreadState::joinThreadPool(bool isMain)
    do {
       processPendingDerefs();
       // now get the next command to be processed, waiting if necessary
       result = getAndExecuteCommand();

       if (result < NO_ERROR && result != TIMED_OUT && result != -ECONNREFUSED && result != -EBADF) {
           ALOGE("getAndExecuteCommand(fd=%d) returned unexpected error %d, aborting",
                 mProcess->mDriverFD, result);
           abort();
       }
       
       // Let this thread exit the thread pool if it is no longer
       // needed and it is not the main process thread.
       if(result == TIMED_OUT && !isMain) {
           break;
       }
   } while (result != -ECONNREFUSED && result != -EBADF);

可以知道其中存在dowhile循环,首先分析其中的getAndExecuteCommand。

status_t IPCThreadState::getAndExecuteCommand()
	/*接收数据*/
	result = talkWithDriver();
		ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr)
	/*处理数据*/
	result = executeCommand(cmd);

到这里IPCThreadState::self()->joinThreadPool();//主线程基本分析完成,下面我么来看看:

ProcessState::self()->startThreadPool();//创建一个子线程

进入startThreadPool函数:

void ProcessState::startThreadPool()
	spawnPooledThread(true);
		/*sp<Thread> t = new PoolThread(isMain)派生于Thread,可以知道其为一个线程*/
		sp<Thread> t = new PoolThread(isMain);
		/*其相当于执行PoolThread中的threadLoop函数*/
		t->run(name.string());

上面提过t->run(name.string())相当于执行PoolThread中的threadLoop函数,那么我们看看threadLoop:

virtual bool threadLoop()
	IPCThreadState::self()->joinThreadPool(mIsMain);

可以看到执行和主线程一样的代码,但是这句代码,是在子线程之中执行的,然后进入一个循环。即子线程之中,存在两个循环。

下面我们分析addService的过程,以及IPCThreadState::self()->joinThreadPool()接收到数据之后是如何处理的。

那么我们以下共3个问题需要解决
1.addService是如何添加服务的
2.server如何分辨client想使用那一个服务
3.怎么调用HelloService所提供的函数。

1.addService是如何添加服务的:
对于不同的服务,构造flat_binder_object结构体,里面的.binder/.cookie对应的服务不一样,其值也不一样。在IServiceManager.cpp文件中:

 virtual status_t addService(const String16& name, const sp<IBinder>& service,bool allowIsolated)
 	/*service = sp<IBinder>& service*/
 	data.writeStrongBinder(service);
 		/*这里val = service = new BnhelloService*/
 		return flatten_binder(ProcessState::self(), val, this);
 			flat_binder_object obj; 
 			/*local =this = new BnhelloService*/
 			IBinder *local = binder->localBinder();
 			obj.type = BINDER_TYPE_BINDER;
            obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs());
            /*new BnhelloService*/
            obj.cookie = reinterpret_cast<uintptr_t>(local);
 	status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);

2.server如何分辨client想使用那一个服务
server收到数据里含有flat_binder_object结构体,他可以根据.binder/.cookie分辨client想使用哪一个服务。把.cookie转换为Bnxxx对象,然后调用他的函数,下面我们跟踪一下源码(在IPCThreadState循环中,接收到数据之后会执行):

status_t IPCThreadState::getAndExecuteCommand()
	result = executeCommand(cmd);
		case BR_TRANSACTION:
			/*根据cookie构造了一个BBinder对象指针,调用其中的transact函数*/
			error = reinterpret_cast<Binder*>(tr.cookie)->transact(tr.code, buffer,&reply, tr.flags);

其上的transact实现如下(Binder.cpp):

status_t BBinder::transact(
	/*其会根据code值,调用不同的函数。*/
	err = onTransact(code, data, reply, flags);
		
  • 6
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

江南才尽,年少无知!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值