Android学习(三)Binder IPC机制(2)

Binder IPC机制

BpBinderNative层的Binder代理,最后会由javaObjectForIBinder转化为Java层的BinderProxy,其构造函数:

/* \Android4.4\frameworks\native\libs\binder\BpBinder.cpp*/

BpBinder::BpBinder(int32_t handle)

    : mHandle(handle)à如果是ServiceManagerhandle0

    , mAlive(1)

    , mObitsSent(0)

    , mObituaries(NULL)

{

    ALOGV("Creating BpBinder %p handle %d\n", this, mHandle);

 

    extendObjectLifetime(OBJECT_LIFETIME_WEAK);

    IPCThreadState::self()->incWeakHandle(handle);

}

/* \Android4.4\frameworks\native\libs\binder\BpBinder.h*/中有如下定义:

class BpBinder : public IBinder

BpBinder继承自IBinder,而

/* \Android4.4\frameworks\native\include\binder\IBinder.h*/

class IBinder : public virtual RefBase

可见BpBinder所使用的引用计数基类是RefBase

RefBase中,可以通过extendObjectLifetime来设置lifetime,有三种lifetime

  • default(0),强引用和弱引用的默认行为,不管弱应用计数的值为多少,只要强引用计数的值为0,就释放对象

  • OBJECT_LIFETIME_WEAK,在这种状态下,如果强引用为0时,对象不会被释放,只有在弱引用计数为0的情况下,对象才会被释放

  • OBJECT_LIFETIME_WEAK | OBJECT_LIFETIME_FOREVER,在这种状态下,对象永不会释放

进入到IPCThreadState的分析:

/* \Android4.4\frameworks\native\libs\binder\IPCThreadState.cpp*/

static pthread_mutex_t gTLSMutex = PTHREAD_MUTEX_INITIALIZER;à 静态初始化互斥锁

static bool gHaveTLS = false;à初始值为false

static pthread_key_t gTLS = 0;

static bool gShutdown = false;

IPCThreadState* IPCThreadState::self()

{

    if (gHaveTLS) {

restart:

        const pthread_key_t k = gTLS;

        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;

}

同一进程中的全局变量是可以在多个线程中访问到的,但线程中访问这些变量需要用到同步机制,在一定程度上降低了执行效率,有些变量只希望在本线程中是全局的,TLSThead Local Storage)保证某个变量仅在自己线程内访问有效,而其他线程中得到的是这个变量的独立复本。

self函数中,当第一次被调用时,gHaveTLSfalse,因此不会进入第一个if判断中,也不会创建IPCThreadState,但会进入第二个if判断启动TLS,然后返回restart处新建一个IPCThreadState。当以后再被调用,gHaveTLStrue:如果本线程已经创建过IPCThreadState,那么pthread_getspecific不为空;否则返回一个新建的IPCThreadState。从而有效保证了线程单实例的目的。

/* \Android4.4\frameworks\native\libs\binder\IPCThreadState.cpp*/

IPCThreadState::IPCThreadState()

    : mProcess(ProcessState::self()),àProcessState整个进程只有一个

      mMyThreadId(androidGetTid()),à当前线程id

      mStrictModePolicy(0),

      mLastTransactionBinderFlags(0)

{

    pthread_setspecific(gTLS, this);

    clearCaller();

    mIn.setDataCapacity(256);àmIn是个Parcel,用于接收Binder发过来的数据,最大容量为256

    mOut.setDataCapacity(256);àmOut也是个Parcel,用于存储发给Binder的数据,最大容量256

}

BpBinder构造函数中,调用了IPCThreadStateincWeakHandle用于增加Binder Service的弱引用计数值,实际上是向Binder驱动发送了一个BC_INCREFS命令。

/* \Android4.4\frameworks\native\libs\binder\IPCThreadState.cpp*/

void IPCThreadState::incWeakHandle(int32_t handle)

{

    LOG_REMOTEREFS("IPCThreadState::incWeakHandle(%d)\n", handle);

    mOut.writeInt32(BC_INCREFS);

    mOut.writeInt32(handle);

}

还有decWeakHandleincStrongHandledecStrongHandleBinder协议中的指令对应。

IPCThreadState负责与Binder驱动进行具体的命令交互,ProcessState负责打开Binder节点并做mmap

IPCThreadState中的transact函数是非常重要的。前面一直以ServiceManager中的getService()方法来追踪代码,流程如下:

getService@ServiceManagerProxyàtransact@BinderProxyàtransact@BpBinderàtransact@IPCThreadState

/* \Android4.4\frameworks\native\libs\binder\IPCThreadState.cpp*/

status_t IPCThreadState::transact(int32_t handle,

                                  uint32_t code, const Parcel& data,

                                  Parcel* reply, uint32_t flags)

{

}

针对getServicetransact函数参数如下:

  • handle0

  • codeGET_SERVICE_TRANSACTION

  • data为一个Parcel包含要查找的服务名

  • flag0

 

/* \Android4.4\frameworks\native\libs\binder\IPCThreadState.cpp*/

status_t IPCThreadState::transact(int32_t handle,

                                  uint32_t code, const Parcel& data,

                                  Parcel* reply, uint32_t flags)

{

    status_t err = data.errorCheck();à检查data是否有效

 

flags |= TF_ACCEPT_FDS;à有四种flag,分别为:

enum transaction_flags {

 TF_ONE_WAY = 0x01,表示当前业务为异步

 TF_ROOT_OBJECT = 0x04,所包含的内容是根对象

 TF_STATUS_CODE = 0x08,所包含内容是32bit状态值

 TF_ACCEPT_FDS = 0x10,容许回复中包含文件描述符

};

    IF_LOG_TRANSACTIONS() {

        TextOutput::Bundle _b(alog);

        alog << "BC_TRANSACTION thr " << (void*)pthread_self() << " / hand "

            << handle << " / code " << TypeCode(code) << ": "

            << indent << data << dedent << endl;

    }

   

    if (err == NO_ERROR) {

        LOG_ONEWAY(">>>> SEND from pid %d uid %d %s", getpid(), getuid(),

            (flags & TF_ONE_WAY) == 0 ? "READ REPLY" : "ONE WAY");

        err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);à writeTransactionData函数整理data,打包为Binder驱动协议规定格式,并把结果写在mout

    }

   

    if (err != NO_ERROR) {

        if (reply) reply->setError(err);

        return (mLastError = err);

    }

   

    if ((flags & TF_ONE_WAY) == 0) {

        #if 0

        if (code == 4) { // relayout

            ALOGI(">>>>>> CALLING transaction 4");

        } else {

            ALOGI(">>>>>> CALLING transaction %d", code);

        }

        #endif

        if (reply) {

            err = waitForResponse(reply);à waitForResponse函数要实现三个功能:

  • BC_TRANSACTION属于BINDER_WRITE_READ的子命令,数据外需要包裹一层描述信息

  • 发送数据

  • 实现Binder IPC的阻塞通信

        } else {

            Parcel fakeReply;

            err = waitForResponse(&fakeReply);

        }

        #if 0

        if (code == 4) { // relayout

            ALOGI("<<<<<< RETURNING transaction 4");

        } else {

            ALOGI("<<<<<< RETURNING transaction %d", code);

        }

        #endif

       

        IF_LOG_TRANSACTIONS() {

            TextOutput::Bundle _b(alog);

            alog << "BR_REPLY thr " << (void*)pthread_self() << " / hand "

                << handle << ": ";

            if (reply) alog << indent << *reply << dedent << endl;

            else alog << "(none requested)" << endl;

        }

    } else {

        err = waitForResponse(NULL, NULL);

    }

   

    return err;}

/* \Android4.4\frameworks\native\libs\binder\IPCThreadState.cpp*/

status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)

{

    int32_t cmd;

    int32_t err;

 

    while (1) {

        if ((err=talkWithDriver()) < NO_ERROR) break;

        err = mIn.errorCheck();

        if (err < NO_ERROR) break;

        if (mIn.dataAvail() == 0) continue;

       

        cmd = mIn.readInt32();

}

由此可见IPCThreadState中与Binder驱动真正进行通信的就在talkWithDriver中。

/* \Android4.4\frameworks\native\libs\binder\IPCThreadState.cpp*/

status_t IPCThreadState::talkWithDriver(bool doReceive)

{

    if (mProcess->mDriverFD <= 0) {

        return -EBADF;

}

do {

        IF_LOG_COMMANDS() {

            alog << "About to read/write, write size = " << mOut.dataSize() << endl;

        }

#if defined(HAVE_ANDROID_OS)

        if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)à写入指令

            err = NO_ERROR;

        else

            err = -errno;

#else

        err = INVALID_OPERATION;

#endif

通过ioctl来与Binder驱动进行交互,再次分析Binder驱动部分的代码:

/* \linux-3.5\drivers\staging\android\binder.c*/

static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)

{

     int ret;

     struct binder_proc *proc = filp->private_data; àfilp中取出proc变量,即binder_open中动态创建的实例

     struct binder_thread *thread;

     unsigned int size = _IOC_SIZE(cmd);à命令的大小

     void __user *ubuf = (void __user *)arg;

 

     /*printk(KERN_INFO "binder_ioctl: %d:%d %x %lx\n", proc->pid, current->pid, cmd, arg);*/

 

     trace_binder_ioctl(cmd, arg);à注释已解释,打印相关信息

 

     ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);

     if (ret)

           goto err_unlocked;

 

     (此处中断一下,解析wait_event_interruptible函数)

 

Binder的阻塞(或同步操作)就是让调用者进程暂时挂起,直到目标进程返回结果后,Binder再唤醒等待的进程,就是通过wait_event_interruptible完成的。

wait_event_interruptible首先将当前进程的状态设置成TASK_INTERRUPTIBLE,即可中断挂起状态,然后进入schedule调度,由于进程已不是处于可运行状态,所以将不再分配CPU时间,直到被唤醒,醒来后先检查condition是否满足,否则再次中断挂起。

/* \linux-3.5\drivers\staging\android\binder.c*/

static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)

{

binder_lock(__func__);

      thread = binder_get_thread(proc);à binder_get_thread首先想proc中的threads链表查询是否已经添加了当前线程节点,如果没有则插入一个表示当前线程的新节点。threads链表中是按照pid大小排序的,加快了查询速度

           if (thread == NULL) {

           ret = -ENOMEM;

           goto err;

     }

 

     switch (cmd) {

     case BINDER_WRITE_READ: {à读写操作,可以用此向binder中读写数据

           struct binder_write_read bwr;

           if (size != sizeof(struct binder_write_read)) {à判断buff大小是否合适

                 ret = -EINVAL;

                 goto err;

           }

           if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {à从用户空间复制数据

                 ret = -EFAULT;

                 goto err;

           }

           binder_debug(BINDER_DEBUG_READ_WRITE,

                      "binder: %d:%d write %ld at %08lx, read %ld at %08lx\n",

                      proc->pid, thread->pid, bwr.write_size, bwr.write_buffer,

                      bwr.read_size, bwr.read_buffer);

 

           if (bwr.write_size > 0) {à有数据需要写

                 ret = binder_thread_write(proc, thread, (void __user *)bwr.write_buffer, bwr.write_size, &bwr.write_consumed);

                 trace_binder_write_done(ret);

                 if (ret < 0) {à成功返回0,负数表示有错

                      bwr.read_consumed = 0;à读取的数据大小为0

                      if (copy_to_user(ubuf, &bwr, sizeof(bwr)))à复制数据到用户空间

                            ret = -EFAULT;

                      goto err;

                 }

           }

           if (bwr.read_size > 0) {à有数据需要读

                 ret = binder_thread_read(proc, thread, (void __user *)bwr.read_buffer, bwr.read_size, &bwr.read_consumed, filp->f_flags & O_NONBLOCK);à读取用户需要的数据

                 trace_binder_read_done(ret);

                 if (!list_empty(&proc->todo))

                      wake_up_interruptible(&proc->wait);

                 if (ret < 0) {

                      if (copy_to_user(ubuf, &bwr, sizeof(bwr)))

                            ret = -EFAULT;

                      goto err;

                 }

           }

           binder_debug(BINDER_DEBUG_READ_WRITE,

                      "binder: %d:%d wrote %ld of %ld, read return %ld of %ld\n",

                      proc->pid, thread->pid, bwr.write_consumed, bwr.write_size,

                      bwr.read_consumed, bwr.read_size);

           if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {

                 ret = -EFAULT;

                 goto err;

           }

           break;

     }

(后面略…)

    

}

 

由此可见,Binder驱动主要起到中间人的作用,真正处理请求还是Binder ClientBinder Server通信双方。

/* \linux-3.5\drivers\staging\android\binder.c*/

int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread,

                 void __user *buffer, int size, signed long *consumed)

针对getService()场景,主要参数如下:

  • proc:调用者的进程

  • thread:调用者线程

  • buffer:即bwr.write_buffer = (long unsigned int)mOut.data();因而就是writeTransactionData中对mOut写入的数据,主要包含两部分

mOut.writeInt32(cmd);

mOut.write(&tr, sizeof(tr));

cmd就是BC_TRANSACTIONtr是一个binder_transcation_data数据结构的变量

  • size:即bwr.write_size

  • consumed:即bwr.write_consumed

/* \linux-3.5\drivers\staging\android\binder.c*/

int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread,

                 void __user *buffer, int size, signed long *consumed)

{

           case BC_TRANSACTION:

           case BC_REPLY: {

                 struct binder_transaction_data tr;

 

                 if (copy_from_user(&tr, ptr, sizeof(tr)))à从用户空间取得tr结构

                      return -EFAULT;

                 ptr += sizeof(tr);

                 binder_transaction(proc, thread, &tr, cmd == BC_REPLY);à具体执行指令

                 break;

           }

/* \linux-3.5\drivers\staging\android\binder.c*/

static void binder_transaction(struct binder_proc *proc,

                        struct binder_thread *thread,

                        struct binder_transaction_data *tr, int reply)

{

      struct binder_transaction *t;à表示一个transaction操作

      struct binder_work *tcomplete;à表示一个未完的操作。因为一个transaction通常涉及两个进程AB,当AB发送请求后,B需要一段时间来执行;此时相对于A就是一个未完的操作,直到B返回结果后,Binder驱动才会再次启动A来继续执行。

      size_t *offp, *off_end;

      struct binder_proc *target_proc;à目标进程

      struct binder_thread *target_thread = NULL;à目标线程

      struct binder_node *target_node = NULL;

      struct list_head *target_list;

      wait_queue_head_t *target_wait;

      struct binder_transaction *in_reply_to = NULL;

      struct binder_transaction_log_entry *e;

      uint32_t return_error;

      if (reply) {

àBC_REPLY指令代码省略

      } else {à针对BC_TRANSACTION指令代码

           if (tr-> target.handle) {à获取目标对象所对应的target_node

                 struct binder_ref *ref;

                 ref = binder_get_ref(proc, tr->target.handle);

                 if (ref == NULL) {

                      binder_user_error("binder: %d:%d got "

                            "transaction to invalid handle\n",

                            proc->pid, thread->pid);

                      return_error = BR_FAILED_REPLY;

                      goto err_invalid_target_handle;

                 }

                 target_node = ref->node;

           } else {à如果target.handle0,表示targetServiceManager,可以直接使用binder_context_mgr_node这全局变量;否则调用binder_get_ref来查找是否存在一个符合handle要求的node

                 target_node = binder_context_mgr_node;

                 if (target_node == NULL) {

                      return_error = BR_DEAD_REPLY;

                      goto err_no_context_mgr_node;

                 }

           }

           e->to_node = target_node->debug_id;

           target_proc = target_node->proc;à目标进程,找到target_proc

           if (target_proc == NULL) {

                 return_error = BR_DEAD_REPLY;

                 goto err_dead_binder;

           }

           if (!(tr->flags & TF_ONE_WAY) && thread->transaction_stack) {

                 struct binder_transaction *tmp;

                 tmp = thread->transaction_stack;

                 if (tmp->to_thread != thread) {

                      binder_user_error("binder: %d:%d got new "

                            "transaction with bad transaction stack"

                            ", transaction %d has target %d:%d\n",

                            proc->pid, thread->pid, tmp->debug_id,

                            tmp->to_proc ? tmp->to_proc->pid : 0,

                            tmp->to_thread ?

                            tmp->to_thread->pid : 0);

                      return_error = BR_FAILED_REPLY;

                      goto err_bad_call_stack;

                 }

                 while (tmp) {

                      if (tmp->from && tmp->from->proc == target_proc)

                            target_thread = tmp->from;à找到target_thread

                      tmp = tmp->from_parent;

                 }

           }

      }

      if (target_thread) {à得到target_listtarget_wait分别表示todotowait

           e->to_thread = target_thread->pid;

           target_list = &target_thread->todo;

           target_wait = &target_thread->wait;

      } else {

           target_list = &target_proc->todo;

           target_wait = &target_proc->wait;

      }

      e->to_proc = target_proc->pid;

 

      /* TODO: reuse incoming transaction for reply */

      t = kzalloc(sizeof(*t), GFP_KERNEL);à生成一个binder_transaction变量(即t)用于描述本次要进行的transaction(最后将其加入到target_thread->todo中)。这样当目标对象被唤醒时,它可以从这个队列中取出需要做的工作。

      if (t == NULL) {

           return_error = BR_FAILED_REPLY;

           goto err_alloc_t_failed;

      }

      binder_stats_created(BINDER_STAT_TRANSACTION);

 

      tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL);à生成一个binder_work变量(即tcomplete)用于说明当前调用者线程有一个未完成的transaction

      if (!reply && !(tr->flags & TF_ONE_WAY))à以下填写binder_transaction数据

           t->from = thread;

      else

           t->from = NULL;

      t->sender_euid = proc->tsk->cred->euid;

      t->to_proc = target_proc;

      t->to_thread = target_thread;

      t->code = tr->code;

      t->flags = tr->flags;

      t->priority = task_nice(current);

      t->buffer = binder_alloc_buf(target_proc, tr->data_size,

           tr->offsets_size, !reply && (t->flags & TF_ONE_WAY));

      if (t->buffer == NULL) {

           return_error = BR_FAILED_REPLY;

           goto err_binder_alloc_buf_failed;

      }

      t->buffer->allow_user_free = 0;

      t->buffer->debug_id = t->debug_id;

      t->buffer->transaction = t;

      t->buffer->target_node = target_node;

      if (target_node)

           binder_inc_node(target_node, 1, 0, NULL);

 

      offp = (size_t *)(t->buffer->data + ALIGN(tr->data_size, sizeof(void *)));à申请到t->buffer内存后,从用户空间把数据复制过来。因为t->buffer所指向的内存空间和目标对象对象空间是共享的,所以只需复制一次就把数据从Binder Client复制到Binder Server中了

 

      if (copy_from_user(t->buffer->data, tr->dataNaNr.buffer, tr->data_size)) {

           binder_user_error("binder: %d:%d got transaction with invalid "

                 "data ptr\n", proc->pid, thread->pid);

           return_error = BR_FAILED_REPLY;

           goto err_copy_data_failed;

      }

      if (copy_from_user(offp, tr->dataNaNr.offsets, tr->offsets_size)) {

           binder_user_error("binder: %d:%d got transaction with invalid "

                 "offsets ptr\n", proc->pid, thread->pid);

           return_error = BR_FAILED_REPLY;

           goto err_copy_data_failed;

      }

      if (!IS_ALIGNED(tr->offsets_size, sizeof(size_t))) {

           binder_user_error("binder: %d:%d got transaction with "

                 "invalid offsets size, %zd\n",

                 proc->pid, thread->pid, tr->offsets_size);

           return_error = BR_FAILED_REPLY;

           goto err_bad_offset;

      }

      off_end = (void *)offp + tr->offsets_size;

 

      for (; offp < off_end; offp++) {

à很长的一个for循环,用来处理数据中的binder_object对象

          }

      t->work.type = BINDER_WORK_TRANSACTION;

      list_add_tail(&t->work.entry, target_list);

      tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;

      list_add_tail(&tcomplete->entry, &thread->todo);

      if (target_wait)à前面提到t最终会加入到对方todo队列中,tcomplete被加入到调用者自己的todo队列中,然后唤醒目标对象。

           wake_up_interruptible(target_wait);

      return;

 

 

 

 

转载于:https://my.oschina.net/honeyandroid/blog/505038

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值