3 Binder--sayHello之ioctl.md( 二 )


这里折后就是将数据保存在mOut中,这里是怎么保证多线程并发的时的处理呢?稍后我们研究IPC的初始化就知道了 。
1.5 #
从名字也可以猜出来,这里应该就是与.c驱动通信 。
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult){uint32_t cmd;int32_t err;while (1) {// 1.6 显而易见, 与驱动通信if ((err=talkWithDriver()) < NO_ERROR) break;// ......// #1.6中已经通过ioctl与binder驱动通信了,回传的输入也写入了mIn中// 读取的第一个uint32_t的数据代表binder通信类型cmd = (uint32_t)mIn.readInt32();// ......switch (cmd) {case BR_TRANSACTION_COMPLETE:if (!reply && !acquireResult) goto finish;break;case BR_DEAD_REPLY:err = DEAD_OBJECT;goto finish;case BR_FAILED_REPLY:err = FAILED_TRANSACTION;goto finish;case BR_ACQUIRE_RESULT:{ALOG_ASSERT(acquireResult != NULL, "Unexpected brACQUIRE_RESULT");const int32_t result = mIn.readInt32();if (!acquireResult) continue;*acquireResult = result ? NO_ERROR : INVALID_OPERATION;}goto finish;// 一般非oneway的通信就是走的这里case BR_REPLY:{binder_transaction_data tr;// 读取从binder驱动回传的数据err = mIn.read(&tr, sizeof(tr));ALOG_ASSERT(err == NO_ERROR, "Not enough command data for brREPLY");if (err != NO_ERROR) goto finish;if (reply) {if ((tr.flags & TF_STATUS_CODE) == 0) {// 将回传的数据存入reply中reply->ipcSetDataReference(reinterpret_cast(tr.data.ptr.buffer),tr.data_size,reinterpret_cast(tr.data.ptr.offsets),tr.offsets_size/sizeof(binder_size_t),freeBuffer, this);} else {err = *reinterpret_cast(tr.data.ptr.buffer);freeBuffer(nullptr,reinterpret_cast(tr.data.ptr.buffer),tr.data_size,reinterpret_cast(tr.data.ptr.offsets),tr.offsets_size/sizeof(binder_size_t), this);}} else {freeBuffer(nullptr,reinterpret_cast(tr.data.ptr.buffer),tr.data_size,reinterpret_cast(tr.data.ptr.offsets),tr.offsets_size/sizeof(binder_size_t), this);continue;}}goto finish;default:err = executeCommand(cmd);if (err != NO_ERROR) goto finish;break;}}finish:if (err != NO_ERROR) {if (acquireResult) *acquireResult = err;if (reply) reply->setError(err);mLastError = err;}return err;}
1.6 #
status_t IPCThreadState::talkWithDriver(bool doReceive){if (mProcess->mDriverFD < 0) {return -EBADF;}// binder_write_read是一个保存了传输数据以及回传数据信息的结构体binder_write_read bwr;// 判断读缓冲区是否为空const bool needRead = mIn.dataPosition() >= mIn.dataSize();// 仍在从输入缓冲区中剩余的数据中读取数据,并且调用者已请求读取下一个数据,则不编写任何内容const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;// 将待传入的数据存入bwr中,以便通过binder驱动传输bwr.write_size = outAvail;bwr.write_buffer = (uintptr_t)mOut.data();// 如果需要回传的数据时if (doReceive && needRead) {// 读缓冲区大小设置为可接受的最大大小bwr.read_size = mIn.dataCapacity();// 将bwr中读缓冲区指针指向mIn中的data,后续驱动直接将数据填充到这里bwr.read_buffer = (uintptr_t)mIn.data();} else {bwr.read_size = 0;bwr.read_buffer = 0;}// ......do {// .....// 使用ioctl与binder驱动通信, 将bwr存储的信息传输给binder驱动if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)err = NO_ERROR;elseerr = -errno;// .....if (mProcess->mDriverFD < 0) {err = -EBADF;}IF_LOG_COMMANDS() {alog << "Finished read/write, write size = " << mOut.dataSize() << endl;}} while (err == -EINTR);// ......if (err >= NO_ERROR) {// ......if (bwr.read_consumed > 0) {// 如果存在回传的数据,则标记mIn.setDataSize(bwr.read_consumed);mIn.setDataPosition(0);}// ......return NO_ERROR;}return err;}
ok, 到这里我们对通信已经有了一个初步的认知,最核心跨进程的通信手段是通过ioctl这个东东 。