IPCThreadState 详解

来源:互联网 发布:淘宝店招图 编辑:程序博客网 时间:2024/05/17 23:49

IPC是Android的精华,找了个时间,详细分析下IPCThreadState 的组织架构及其功能


初始化:用这个方法,我们可以在每个线程里取得IPCThreadState

IPCThreadState* IPCThreadState::self()
{

    // 全局标志位,代表是否TSD已经建立
    if (gHaveTLS) {
restart:
        const pthread_key_t k = gTLS;

        // 获取线程私有数据,即IPCThreadState本身,没有则创建。  保证每个线程都有相对应的IPCThreadState
        IPCThreadState* st = (IPCThreadState*)pthread_getspecific(k);
        if (st) return st;
        return new IPCThreadState;
    }


    if (gShutdown) return NULL;


    pthread_mutex_lock(&gTLSMutex);
    if (!gHaveTLS) {

        // 如果线程私有数据没建立,则创建一个。
        if (pthread_key_create(&gTLS, threadDestructor) != 0) {
            pthread_mutex_unlock(&gTLSMutex);
            return NULL;
        }
        gHaveTLS = true;
    }
    pthread_mutex_unlock(&gTLSMutex);

    // 创建完,恢复到启始逻辑
    goto restart;
}

看了它的构造函数,明显,这就是为每个线程邦定了个结构体。 


然后,就是IPCThreadState的构造函数,非常简单简洁

IPCThreadState::IPCThreadState()
    : mProcess(ProcessState::self()),
      mMyThreadId(androidGetTid()),
      mStrictModePolicy(0),
      mLastTransactionBinderFlags(0)
{
    pthread_setspecific(gTLS, this);
    clearCaller();
    mIn.setDataCapacity(256);
    mOut.setDataCapacity(256);
}

可以看到,mIn和mOut 直接设了个容量,


接下来总结下各个功能


1. freeBuffer: 
          用于释放空间。  2个用处:
               1)             buffer.ipcSetDataReference 作为释放函数传入  
               2)             BR_REPLY: if no reply
          作为释放函数传入时,分别在传入和传出有体现BR_TRANSACTION and BR_REPLY 
    

           if (parcel != NULL) parcel->closeFileDescriptors();
          检查是否为空, noreply(2) 情况此值为空。 传入(1)此值为this, 当前parsel.   遍寻parsel结构体关闭所有 BINDER_TYPE_FD类型file .

          IPCThreadState* state = self(); 得到当前线程的IPCThreadState, 其实也就是当前结构体

          state->mOut.writeInt32(BC_FREE_BUFFER);
          state->mOut.writeInt32((int32_t)data);
          通过read write 写命令到驱动层,释放结构体。

2. threadDestructor
           用于毁掉这个线程,应该包括各种释放

          self->flushCommands();  ==〉 
           
          // 检查是否打开了底层驱动,如果没,直接返回
          if (mProcess->mDriverFD <= 0)
               return;
          // 与底层交流,试图关闭驱动
          talkWithDriver(false);  细节以后分析,不需要接受命令,但会把当前须传出的命令传下去

          #if defined(HAVE_ANDROID_OS)
               ioctl(self->mProcess->mDriverFD, BINDER_THREAD_EXIT, 0);
          #endif
          直接操纵底层驱动,从驱动层删除了这个线程

3. executeCommand  执行各种命令  命令基本来自驱动层

              case BR_ERROR:
                  result = mIn.readInt32();
                  break;
               从下层读一个32bit, 好象是下面发了个错误信号,上层去读为什么出问题

               case BR_OK:
                  break;
               蛋疼。。

               case BR_ACQUIRE:
                   refs = (RefBase::weakref_type*)mIn.readInt32();
                   obj = (BBinder*)mIn.readInt32();
                   从底层拿这两个结构体上来。
                   obj->incStrong(mProcess.get());
                    真实工作
                   mOut.writeInt32(BC_ACQUIRE_DONE);
                   mOut.writeInt32((int32_t)refs);
                   mOut.writeInt32((int32_t)obj);
                   ref啥也没干,又放回去了
                    
               什么时候会调这个函数呢。。。似乎是一次binder函数结束时搞定
               case BR_RELEASE:
                    mPendingStrongDerefs.push(obj);        mPendingWeakDerefs.push(refs)
                    直接加到这个队列里,应该有个什么地方释放巴

               BR_INCREFS:
                    refs->incWeak(mProcess.get());
                     可以看到refs终于干活了。记得传说,obj 讲的是服务,也就是本地进程,ref是客户端进程, 待严正

               case BR_DECREFS:
                     mPendingWeakDerefs.push(refs)
                    另外一个队列

               case BR_ATTEMPT_ACQUIRE
                    const bool success = refs->attemptIncStrong(mProcess.get());
               这玩干什么的阿。。没找到谁调用的阿。goolge下说没实现。。 这个是用来变弱为强的阿,设计者在想什么啊

               case BR_TRANSACTION:
                    正题~~

                    binder_transaction_data tr;
                    result = mIn.read(&tr, sizeof(tr));
                    从下面读上来的。这是要操作的数据马?

                    Parcel buffer;
                    buffer.ipcSetDataReference(
                    reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
                    tr.data_size,
                    reinterpret_cast<const size_t*>(tr.data.ptr.offsets),
                    tr.offsets_size/sizeof(size_t), freeBuffer, this);
          构造了个parcel, 然后传进来的数据被按进去了

           
            const pid_t origPid = mCallingPid;
            const uid_t origUid = mCallingUid;

            mCallingPid = tr.sender_pid;
            mCallingUid = tr.sender_euid;
                      调用者进程号线程号被记下来的,竟然是实名制。

                      int curPrio = getpriority(PRIO_PROCESS, mMyThreadId);
                            if (gDisableBackgroundScheduling) {
                                    if (curPrio > ANDROID_PRIORITY_NORMAL) {
                                   // We have inherited a reduced priority from the caller, but do not
                                   // want to run in that state in this process.  The driver set our
                                   // priority already (though not our scheduling class), so bounce
                                   // it back to the default before invoking the transaction.
                                        setpriority(PRIO_PROCESS, mMyThreadId, ANDROID_PRIORITY_NORMAL);
                                      }
                            } else {
                                    if (curPrio >= ANDROID_PRIORITY_BACKGROUND) {
                                    // We want to use the inherited priority from the caller.
                                   // Ensure this thread is in the background scheduling class,
                                   // since the driver won't modify scheduling classes for us.
                                   // The scheduling group is reset to default by the caller
                                   // once this method returns after the transaction is complete.
                                             androidSetThreadSchedulingGroup(mMyThreadId,
                                                    ANDROID_TGROUP_BG_NONINTERACT);
                               }
                       }
                       如果启动了线程调控机制, androidSetThreadSchedulingGroup,否则单独设一个线程的优先级。 这里会涉及Linux 的调度概念,比如CFS(Completely Fair Scheduler)
                    
                  Parcel reply;
                  if (tr.target.ptr) {
                       sp<BBinder> b((BBinder*)tr.cookie);
                       const status_t error = b->transact(tr.code, buffer, &reply, tr.flags);
                       if (error < NO_ERROR) reply.setError(error);
                    如果这个BBinder包含了一个可用的object, 即服务存在,则调用服务的transact
                    } else {
                        const status_t error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);
                        if (error < NO_ERROR) reply.setError(error);
                  }
                    如果这个标志位为空,说明调用的是服务进程。service manager被调用。 transact 在这不深入
                  if ((tr.flags & TF_ONE_WAY) == 0) {
                          LOG_ONEWAY("Sending reply to %d!", mCallingPid);
                          sendReply(reply, 0);
                      } else {
                          LOG_ONEWAY("NOT sending reply to %d!", mCallingPid);
                      }
                         这个好理解,transact 的返回值被封装在reply再传回driver.

                case BR_DEAD_BINDER
                      BpBinder *proxy = (BpBinder*)mIn.readInt32();
                      proxy->sendObituary();
                      mOut.writeInt32(BC_DEAD_BINDER_DONE);
                      mOut.writeInt32((int32_t)proxy);
                         出了个新概念,BpBinder~~  传说他是跟BBinder对应的,不过这里他代表着一个Binder, 可惜这里表示的是个死binder
                         然后这个家伙发出讣告,通知所有的注册的deathnotifier~~~ 基本上是清理工作

          case BR_CLEAR_DEATH_NOTIFICATION_DONE:
             当前task取消订阅binder死亡通知成功之后的得到回复命令-- google said
             还没看到相关细节
     
           case BR_SPAWN_LOOPER:
                       mProcess->spawnPooledThread(false);
                       这个函数是用来注册用的阿,那参数如果是true 就是主函数,否则就是加入循环。  具体用法待分析

                   还有几个小case,没意义,不分析了

4. 往上看是个将就的表达,这 the_context_object全局变量表示的是总service,可笑的是竟然找不到谁调了这个setTheContextObject
如果不是这个方法被弃用了,就是什么特殊手段在某些地方定义的。。。 等以后碰到了再说吧

sp<BBinder> the_context_object;

void setTheContextObject(sp<BBinder> obj)
{
    the_context_object = obj;
}

5. writeTransactionData     这个函数很重要啊,贯通与驱动的数据通信

     如果没有问题,数据打包封装
    if (err == NO_ERROR) {
        tr.data_size = data.ipcDataSize();
        tr.data.ptr.buffer = data.ipcData();
        tr.offsets_size = data.ipcObjectsCount()*sizeof(size_t);
        tr.data.ptr.offsets = data.ipcObjects();
    } else if (statusBuffer) {
      如果是状态传输,打包状态传输
        tr.flags |= TF_STATUS_CODE;
        *statusBuffer = err;
        tr.data_size = sizeof(status_t);
        tr.data.ptr.buffer = statusBuffer;
        tr.offsets_size = 0;
        tr.data.ptr.offsets = NULL;
    } else {
        return (mLastError = err);
    }
    最后是写下去
    mOut.writeInt32(cmd);
    mOut.write(&tr, sizeof(tr));

6. talkWithDriver  这个估计是这个文件里最重要的地方了

          binder_write_read bwr;     负责通信的载体

          const bool needRead = mIn.dataPosition() >= mIn.dataSize();
          dataposition 是数据位置,size是终止位置,当没有数据时,他们应该相等

          const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
      outavail 由2个因素决定,doreceive 是传进来的,不接受的时候,可以有数据输出 
                            needread, 是上个函数算出来的,读buffer为空,没有数据在读进来

      当地英文解释说,写操作力图避免与读操作同时发生

      bwr.write_size = outAvail;
      bwr.write_buffer = (long unsigned int)mOut.data();
      写入的一次付值,如果write_size为0, 则不会有写的实际操作发生

      if (doReceive && needRead) {
        bwr.read_size = mIn.dataCapacity();
        bwr.read_buffer = (long unsigned int)mIn.data();
    } else {
        bwr.read_size = 0;
        bwr.read_buffer = 0;
    }
      如果需要读,且读buffer确实为空,则设置准备读

      if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;
      如果读写皆为0, 则返回

      bwr.write_consumed = 0;
`         bwr.read_consumed = 0;
           status_t err;
           do {

                  if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
                           err = NO_ERROR;
                  else
                           err = -errno;

           } while (err == -EINTR);
      直接操作ioctl 与驱动层通信。

 if (err >= NO_ERROR) {
              if (bwr.write_consumed > 0) {
                  if (bwr.write_consumed < (ssize_t)mOut.dataSize())
                       mOut.remove(0, bwr.write_consumed);
                  else
                       mOut.setDataSize(0);
                   }
              if (bwr.read_consumed > 0) {
                   mIn.setDataSize(bwr.read_consumed);
                   mIn.setDataPosition(0);
              } 
        如果读写出错,这里做了下错误处理。没什么内容。

说道这里,就是说所有mOut写下去的数据都需要talkwithdriver 真正的写下去, mIn也是调完talk才可以用的

7.waitForResponse 用于传数据下去后,等待底层回复

          while (1) 程序起手死循环,等确定条件发生时break

          if ((err=talkWithDriver()) < NO_ERROR) break;
                  err = mIn.errorCheck();
                  if (err < NO_ERROR) break;
                  if (mIn.dataAvail() == 0) continue;
                  直接与底层交互,有错误推出,没数据传入继续等待

                  cmd = mIn.readInt32();
                  成功读入数据

                  switch (cmd) {
                  根据不同返回的命令进行相关工作
               
                    case BR_TRANSACTION_COMPLETE:
                         if (!reply && !acquireResult) goto finish;
              这个逻辑应该有上下文,当传入的两个参数皆为空才返回。应该有些条件约束。不过他表达的是transaction 完成

            case BR_DEAD_REPLY:
                           err = DEAD_OBJECT;
                           goto finish;
                    返回错误码,应该是服务线程已经不存在了

                    case BR_FAILED_REPLY:
                           err = FAILED_TRANSACTION;
           返回错误码,传输失败

          case BR_ACQUIRE_RESULT:
            {
                LOG_ASSERT(acquireResult != NULL, "Unexpected brACQUIRE_RESULT");
                const int32_t result = mIn.readInt32();
                if (!acquireResult) continue;
                *acquireResult = result ? NO_ERROR : INVALID_OPERATION;
            }
            返回结果,暂时搞不懂下层在什么情况下返回这个,难道是某种状态查询?

            
          case BR_REPLY:
            {
                binder_transaction_data tr;
                err = mIn.read(&tr, sizeof(tr));
                if (err != NO_ERROR) goto finish;
                真的读进了个返回数据

                if (reply) { // 参数
                    if ((tr.flags & TF_STATUS_CODE) == 0) {
                        reply->ipcSetDataReference(
                            reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
                            tr.data_size,
                            reinterpret_cast<const size_t*>(tr.data.ptr.offsets),
                            tr.offsets_size/sizeof(size_t),
                            freeBuffer, this);
                         需要搞明白这是要干什么,不满足的情况都释放掉
                    } else {
                        err = *static_cast<const status_t*>(tr.data.ptr.buffer);
                        freeBuffer(NULL,
                            reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
                            tr.data_size,
                            reinterpret_cast<const size_t*>(tr.data.ptr.offsets),
                            tr.offsets_size/sizeof(size_t), this);
                    }
                } else {
                    freeBuffer(NULL,
                        reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
                        tr.data_size,
                        reinterpret_cast<const size_t*>(tr.data.ptr.offsets),
                        tr.offsets_size/sizeof(size_t), this);
                    continue;
                }
            }
            goto finish;
             这个要反过来再讲一讲


8. sendReply 这个函数用在BR_TRANSACTION, 当服务线程工作时,错误值,打包返回driver, 最后到client thread

         err = writeTransactionData(BC_REPLY, flags, -1, 0, reply, &statusBuffer);
         if (err < NO_ERROR) return err;

         return waitForResponse(NULL, NULL);

9. clearDeathNotification/requestDeathNotification
          相当于某种程度的注册,应该是binder死亡后的相关处理

10. transact

          err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
          着要是调到这个函数。前面已经分析过
          他增加了下对wait respond 的各种等待
11. joinThreadPool 这是这个线程的主逻辑 网上有很多文章分析这个

          mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
          通过BC_ENTER_LOOPER 或者BC_REGISTER_LOOPER确定是服务线程还是各个services.

          androidSetThreadSchedulingGroup(mMyThreadId, ANDROID_TGROUP_DEFAULT);
          设定策略层,线程调度策略

          如果没有数据传入,清空那obj和ref对列
        // When we've cleared the incoming command queue, process any pending derefs
        if (mIn.dataPosition() >= mIn.dataSize()) {
            size_t numPending = mPendingWeakDerefs.size();
            if (numPending > 0) {
                for (size_t i = 0; i < numPending; i++) {
                    RefBase::weakref_type* refs = mPendingWeakDerefs[i];
                    refs->decWeak(mProcess.get());
                }
                mPendingWeakDerefs.clear();
            }

            numPending = mPendingStrongDerefs.size();
            if (numPending > 0) {
                for (size_t i = 0; i < numPending; i++) {
                    BBinder* obj = mPendingStrongDerefs[i];
                    obj->decStrong(mProcess.get());
                }
                mPendingStrongDerefs.clear();
            }
        }

        与驱动交互
        result = talkWithDriver();

        如果有数据传入,执行相关命令
        if (result >= NO_ERROR) {
            size_t IN = mIn.dataAvail();
            if (IN < sizeof(int32_t)) continue;
            cmd = mIn.readInt32();
            IF_LOG_COMMANDS() {                     
                alog << "Processing top-level Command: "
                    << getReturnString(cmd) << endl;
            }
   
   
            result = executeCommand(cmd);
        }

        基本就是这个逻辑反复循环。。


到这,这里的基本内容就算理清了














原创粉丝点击