Android的应用程序包括Java应用及本地应用,Java应用运行在davik虚拟机中,由zygote进程来创建启动,而本地服务应用在Android系统启动时,通过配置init.rc文件来由Init进程启动。Zygote启动Android应用程序的过程请查看文章Zygote孵化应用进程过程的源码分析,关于本地应用服务的启动过程在Android Init进程源码分析中有详细的介绍。无论是Android的Java应用还是本地服务应用程序,都支持Binder进程间通信机制,本文将介绍Android应用程序是如何启动Binder线程来支持Binder进程间通信的相关内容。

在zygote启动Android应用程序时,会调用zygoteInit函数来初始化应用程序运行环境,比如虚拟机堆栈大小,Binder线程的注册等

public static final void zygoteInit(int targetSdkVersion, String[] argv)throws ZygoteInit.MethodAndArgsCaller {redirectLogStreams();commonInit();//启动Binder线程池以支持Binder通信nativeZygoteInit();applicationInit(targetSdkVersion, argv);
}

nativeZygoteInit函数用于创建线程池,该函数是一个本地函数,其对应的JNI函数为

frameworks\base\core\jni\AndroidRuntime.cpp

static void com_android_internal_os_RuntimeInit_nativeZygoteInit(JNIEnv* env, jobject clazz)
{gCurRuntime->onZygoteInit();
}

变量gCurRuntime的类型是AndroidRuntime,AndroidRuntime类的onZygoteInit()函数是一个虚函数,在AndroidRuntime的子类AppRuntime中被实现

frameworks\base\cmds\app_process\App_main.cpp

virtual void onZygoteInit()
{sp<ProcessState> proc = ProcessState::self();ALOGV("App process: starting thread pool.\n");proc->startThreadPool();
}

函数首先得到ProcessState对象,然后调用它的startThreadPool()函数来启动线程池。

void ProcessState::startThreadPool()
{AutoMutex _l(mLock);if (!mThreadPoolStarted) {mThreadPoolStarted = true;spawnPooledThread(true);}
}

mThreadPoolStarted是线程池启动标志位,在startThreadPool()函数中被设置为true

void ProcessState::spawnPooledThread(bool isMain)
{if (mThreadPoolStarted) {//统计启动的Binder线程数量int32_t s = android_atomic_add(1, &mThreadPoolSeq);char buf[16];snprintf(buf, sizeof(buf), "Binder_%X", s);ALOGV("Spawning new pooled thread, name=%s\n", buf);//创建一个PoolThread线程sp<Thread> t = new PoolThread(isMain);//启动线程t->run(buf);}
}

PoolThread是Thread的子类,PoolThread类的定义如下

class PoolThread : public Thread
{
public:PoolThread(bool isMain): mIsMain(isMain){}protected:virtual bool threadLoop(){IPCThreadState::self()->joinThreadPool(mIsMain);return false;}const bool mIsMain;
};

通过t->run(buf)来启动该线程,并且重写了线程执行函数threadLoop(),当线程启动运行后,threadLoop()被调用执行

virtual bool threadLoop()
{IPCThreadState::self()->joinThreadPool(mIsMain);return false;
}

直接执行joinThreadPool(mIsMain)函数将线程注册到Binder驱动程序中,mIsMain = true表示当前线程是主线程

void IPCThreadState::joinThreadPool(bool isMain)
{mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);//设置线程组androidSetThreadSchedulingGroup(mMyThreadId, ANDROID_TGROUP_DEFAULT);status_t result;do {int32_t cmd;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();}}//通知Binder驱动线程进入循环执行result = talkWithDriver();if (result >= NO_ERROR) {size_t IN = mIn.dataAvail();if (IN < sizeof(int32_t)) continue;//读取并执行Binder驱动返回来的命令cmd = mIn.readInt32();result = executeCommand(cmd);}androidSetThreadSchedulingGroup(mMyThreadId, ANDROID_TGROUP_DEFAULT);// 如果该线程不是主线程并且不在需要该线程时,线程退出if(result == TIMED_OUT && !isMain) {break;}} while (result != -ECONNREFUSED && result != -EBADF);//通知Binder驱动线程退出mOut.writeInt32(BC_EXIT_LOOPER);talkWithDriver(false);
}

函数首先向IPCThreadState对象的mOut Parcel对象中写入BC_ENTER_LOOPER Binder协议命,该命令告诉Binder驱动该线程进入循环执行状态

mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);

然后调用函数result = talkWithDriver()将mOut中的数据发送到Binder驱动程序中

status_t IPCThreadState::talkWithDriver(bool doReceive)
{ALOG_ASSERT(mProcess->mDriverFD >= 0, "Binder driver is not opened");binder_write_read bwr;const bool needRead = mIn.dataPosition() >= mIn.dataSize();const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;bwr.write_size = outAvail;bwr.write_buffer = (long unsigned int)mOut.data();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;}// Return immediately if there is nothing to do.if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;bwr.write_consumed = 0;bwr.read_consumed = 0;status_t err;do {
#if defined(HAVE_ANDROID_OS)if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)err = NO_ERROR;elseerr = -errno;
#elseerr = INVALID_OPERATION;
#endif} while (err == -EINTR);if (err >= NO_ERROR) {if (bwr.write_consumed > 0) {if (bwr.write_consumed < (ssize_t)mOut.dataSize())mOut.remove(0, bwr.write_consumed);elsemOut.setDataSize(0);}if (bwr.read_consumed > 0) {mIn.setDataSize(bwr.read_consumed);mIn.setDataPosition(0);}return NO_ERROR;}return err;
}

通过ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr)进入Binder驱动中,此时执行的Binder命令为BINDER_WRITE_READ,发送给Binder驱动的数据保存在binder_write_read结构体中
发送的数据为
bwr.write_size = outAvail;
bwr.write_buffer = (long unsigned int)mOut.data();
bwr.read_size = mIn.dataCapacity();
bwr.read_buffer = (long unsigned int)mIn.data();
在执行binder_ioctl()函数时先执行Binder驱动写在执行Binder驱动读操作

static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{int ret;struct binder_proc *proc = filp->private_data;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);*/ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);if (ret)return ret;mutex_lock(&binder_lock);thread = binder_get_thread(proc);if (thread == NULL) {ret = -ENOMEM;goto err;}switch (cmd) {case BINDER_WRITE_READ: {struct binder_write_read bwr;if (size != sizeof(struct binder_write_read)) {ret = -EINVAL;goto err;}if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {ret = -EFAULT;goto err;}if (bwr.write_size > 0) {ret = binder_thread_write(proc, thread, (void __user *)bwr.write_buffer, bwr.write_size, &bwr.write_consumed);if (ret < 0) {bwr.read_consumed = 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);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;}}if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {ret = -EFAULT;goto err;}break;}default:ret = -EINVAL;goto err;}ret = 0;
err:if (thread)thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN;mutex_unlock(&binder_lock);wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);if (ret && ret != -ERESTARTSYS)printk(KERN_INFO "binder: %d:%d ioctl %x %lx returned %d\n", proc->pid, current->pid, cmd, arg, ret);return ret;
}

在内核数据发送缓冲区中保存了BC_ENTER_LOOPER命令,因此在执行binder_thread_write函数时,只处理BC_ENTER_LOOPER命令

int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread,void __user *buffer, int size, signed long *consumed)
{uint32_t cmd;void __user *ptr = buffer + *consumed;void __user *end = buffer + size;while (ptr < end && thread->return_error == BR_OK) {if (get_user(cmd, (uint32_t __user *)ptr))return -EFAULT;ptr += sizeof(uint32_t);if (_IOC_NR(cmd) < ARRAY_SIZE(binder_stats.bc)) {binder_stats.bc[_IOC_NR(cmd)]++;proc->stats.bc[_IOC_NR(cmd)]++;thread->stats.bc[_IOC_NR(cmd)]++;}switch (cmd) {case BC_ENTER_LOOPER:if (thread->looper & BINDER_LOOPER_STATE_REGISTERED) {thread->looper |= BINDER_LOOPER_STATE_INVALID;}thread->looper |= BINDER_LOOPER_STATE_ENTERED;break;default:printk(KERN_ERR "binder: %d:%d unknown command %d\n",proc->pid, thread->pid, cmd);return -EINVAL;}*consumed = ptr - buffer;}return 0;
}

BC_ENTER_LOOPER命令下的处理非常简单,仅仅是将当前线程binder_thread的状态标志位设置为BINDER_LOOPER_STATE_ENTERED,binder_thread_write函数执行完后,由于bwr.read_size > 0,因此binder_ioctl()函数还会执行Binder驱动读

static int binder_thread_read(struct binder_proc *proc,struct binder_thread *thread,void  __user *buffer, int size,signed long *consumed, int non_block)
{void __user *ptr = buffer + *consumed;void __user *end = buffer + size;int ret = 0;int wait_for_proc_work;//向用户空间发送一个BR_NOOPif (*consumed == 0) {if (put_user(BR_NOOP, (uint32_t __user *)ptr))return -EFAULT;ptr += sizeof(uint32_t);}
retry://由于当前线程首次注册到Binder驱动中,因此事务栈和待处理队列都为空,wait_for_proc_work = truewait_for_proc_work = thread->transaction_stack == NULL && list_empty(&thread->todo);//在初始化binder_thread时,return_error被初始化为BR_OK,因此这里为falseif (thread->return_error != BR_OK && ptr < end) {if (thread->return_error2 != BR_OK) {if (put_user(thread->return_error2, (uint32_t __user *)ptr))return -EFAULT;ptr += sizeof(uint32_t);if (ptr == end)goto done;thread->return_error2 = BR_OK;}if (put_user(thread->return_error, (uint32_t __user *)ptr))return -EFAULT;ptr += sizeof(uint32_t);thread->return_error = BR_OK;goto done;}//设置当前线程的运行状态为BINDER_LOOPER_STATE_WAITINGthread->looper |= BINDER_LOOPER_STATE_WAITING;if (wait_for_proc_work)proc->ready_threads++;mutex_unlock(&binder_lock);if (wait_for_proc_work) {//在注册Binder线程时已经设置为BINDER_LOOPER_STATE_ENTERED,因此这里的条件为falseif (!(thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED))) {wait_event_interruptible(binder_user_error_wait,binder_stop_on_user_error < 2);}//设置线程默认优先级binder_set_nice(proc->default_priority);if (non_block) {if (!binder_has_proc_work(proc, thread))ret = -EAGAIN;} else//在为当前线程创建binder_thread时,线程状态标志位被初始化为BINDER_LOOPER_STATE_NEED_RETURN,因此binder_has_proc_work函数返回true,当前线程睡眠在当前进程的等待队列中ret = wait_event_interruptible_exclusive(proc->wait, binder_has_proc_work(proc, thread));} else {...}mutex_lock(&binder_lock);if (wait_for_proc_work)proc->ready_threads--;thread->looper &= ~BINDER_LOOPER_STATE_WAITING;if (ret)return ret;while (1) {uint32_t cmd;struct binder_transaction_data tr;struct binder_work *w;struct binder_transaction *t = NULL;if (!list_empty(&thread->todo))w = list_first_entry(&thread->todo, struct binder_work, entry);else if (!list_empty(&proc->todo) && wait_for_proc_work)w = list_first_entry(&proc->todo, struct binder_work, entry);else {if (ptr - buffer == 4 && !(thread->looper & BINDER_LOOPER_STATE_NEED_RETURN)) /* no data added */goto retry;break;}if (end - ptr < sizeof(tr) + 4)break;switch (w->type) {case BINDER_WORK_TRANSACTION: break;case BINDER_WORK_TRANSACTION_COMPLETE: break;case BINDER_WORK_NODE: break;case BINDER_WORK_DEAD_BINDER:case BINDER_WORK_DEAD_BINDER_AND_CLEAR:case BINDER_WORK_CLEAR_DEATH_NOTIFICATION: break;}done:*consumed = ptr - buffer;if (proc->requested_threads + proc->ready_threads == 0 &&proc->requested_threads_started < proc->max_threads &&(thread->looper & (BINDER_LOOPER_STATE_REGISTERED |BINDER_LOOPER_STATE_ENTERED))) {proc->requested_threads++;if (put_user(BR_SPAWN_LOOPER, (uint32_t __user *)buffer))return -EFAULT;}return 0;
}

这样就将当前线程注册到了Binder驱动中,同时该线程进入睡眠等待客户端请求,当有客户端请求到来时,该Binder线程被唤醒,接收并处理客户端的请求。因此Android应用程序通过注册Binder线程来支持Binder进程间通信机制。

Android应用程序启动Binder线程源码分析相关推荐

  1. Rtthread线程源码分析

    Rtthread线程源码分析 /*** This function will create a thread object and allocate thread object memory* and ...

  2. Android App签名(证书)校验过程源码分析

      Android App安装是需要证书支持的,我们在Eclipse或者Android Studio中开发App时,并没有注意关于证书的事,也能正确安装App.这是因为使用了默认的debug证书.在A ...

  3. Android—OkHttp同步异步请求过程源码分析与拦截器

    OkHttp同步请求步骤: 创建OkHttpClient,客户对象 创建Request,请求主体,在请求主体设置请求的url,超时时间等 用newCall(request)将Reuqest对象封装成C ...

  4. 【生产者篇】 sender线程源码分析--1

    主要内容: sender线程简单介绍 sender线程的初始化和开启时机 初始化源码分析 开启时机和运行方式源码分析 总结 run方法执行流程分析 run方法源码 Sender线程run方法图解 细节 ...

  5. RocketMQ:NameServer架构设计以及启动关闭流程源码分析

    文章目录 NameServer 1.架构设计 2.核心类与配置 3.启动与关闭流程 3.1.步骤一 3.2.步骤二 3.3.步骤三 NameServer 1.架构设计 消息中间件的设计思路一般都是基于 ...

  6. Android系统默认Home应用程序(Launcher)的启动过程源码分析

    在前面一篇文章中,我们分析了Android系统在启动时安装应用程序的过程,这些应用程序安装好之后,还须要有一个Home应用程序来负责把它们在桌面上展示出来,在Android系统中,这个默认的Home应 ...

  7. Activity启动流程源码分析(基于Android N)

    Activity启动流程源码分析 一个Activity启动分为两种启动方式,一种是从Launcher界面上的图标点击启动,另一种是从一个Activity中设置按钮点击启动另外一个Activity.这里 ...

  8. Android uevent进程源码分析

    在Android Init进程源码分析中讲到init进程会依次执行被加入到待执行队列action_queue中的Action,在init.rc中我们有这么一段配置: 11 on early-init1 ...

  9. Android服务查询完整过程源码分析

    Android服务注册完整过程源码分析中从上到下详细分析了Android系统的服务注册过程,本文同样针对AudioService服务来介绍Android服务的查询过程. 客户端进程数据发送过程 pri ...

最新文章

  1. 自动识别口罩佩戴模型在线教学,抗疫在家涨知识!
  2. yzmcms图片自适应代码_[ NeurIPS 2020 ] 一叶知秋 —— 基于“单目标域样本”的领域自适应方法...
  3. 十种可以成为知己的异性
  4. 【转】Git连接oschina管理代码版本
  5. JS回调函数、真实举例
  6. 不吹不黑,这5款浏览器安全无广告无弹窗,亲测好用
  7. 【LaTeX入门】15 在文章中添加脚注
  8. java 以10为底的对数_log以10为底0.5的对数怎么算
  9. Linux 磁盘清理
  10. 20162327WJH使用队列:模拟票务站台代码分析
  11. 【机器学习】详解 EfficientNet
  12. 【Scala】Scala中的模式匹配、类型参数与隐式转换
  13. Centos7 逻辑卷 物理卷 卷组 实践
  14. 在线客服系统的功能有哪些是非常重要的?
  15. 平均年薪60.8万,程序员拿下这个证书有多吃香?!
  16. Tecplot —— 探针提取数据集任一点数值
  17. markdown笔记(一)—— 首行缩进和换行
  18. c 全国计算机二级考试真题及答案,全国计算机二级考试《C语言》真题练习及答案...
  19. 卫士处刑者冠军css3边,天赋升华_流放之路3.9卫士流血BD_3.9冠军流血弓刷图BD攻略_3DM网游...
  20. cs/bs软件架构优缺点

热门文章

  1. 生活随笔:怀念大学时代
  2. 剑指offer(C++)-JZ77:按之字形顺序打印二叉树(数据结构-树)
  3. c语言中十进制与十六进制转换_小猿圈分享-java-十进制、八进制、十六进制数互相转换...
  4. 武大金融工程和计算机专业,求解!武大的金融工程可以排第几
  5. java arraystoreexception_java基础面试
  6. 《python接口自动化测试》笔记
  7. 自学大数据前,零基础,三个月,找到一份测试工作
  8. Mybatis的复习
  9. android 第三方裁剪,Android裁剪意向不适用于系统图库应用程序,但适用于第三方应用程序...
  10. 树状结构搜索功能_百度搜索算法全解析SEO课程笔记