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(tr.data.ptr.buffer),                     tr.data_size,                     reinterpret_cast(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 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 the_context_object;

void setTheContextObject(sp 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(tr.data.ptr.buffer),
                            tr.data_size,
                            reinterpret_cast(tr.data.ptr.offsets),
                            tr.offsets_size/sizeof(size_t),
                            freeBuffer, this);
                         需要搞明白这是要干什么,不满足的情况都释放掉
                    } else {
                        err = *static_cast(tr.data.ptr.buffer);
                        freeBuffer(NULL,
                            reinterpret_cast(tr.data.ptr.buffer),
                            tr.data_size,
                            reinterpret_cast(tr.data.ptr.offsets),
                            tr.offsets_size/sizeof(size_t), this);
                    }
                } else {
                    freeBuffer(NULL,
                        reinterpret_cast(tr.data.ptr.buffer),
                        tr.data_size,
                        reinterpret_cast(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);
        }

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

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













更多相关文章

  1. delphi xe5 android 开发数据访问手机端(二)
  2. android中 异步消息处理机制及Handler
  3. Android(安卓)连接Mysql数据库步骤(新手步骤)
  4. android 导出带数据库文件的APK
  5. Android之使用Http协议实现文件上传功能
  6. 说说Android中的Settings.Secure
  7. 包管理系统分析 包管理脚本 /system/bin/pm 解析:
  8. Android(安卓)面试题总结(一)
  9. android远程服务

随机推荐

  1. 开始Android应用程序国内广告盈利模式
  2. Android中Log机制详解
  3. Android开发之旅:环境搭建及HelloWorld
  4. Android(安卓)- 开发实例(16):ListView新
  5. android利用Intent.ACTION_SEND实现简单
  6. system.img镜像转换为system.new.dat + s
  7. 2011.06.23——— android 事件处理机制
  8. Android实时绘制效果(一)
  9. android eclipse setup
  10. 使用命令行编译Qt Android apps