Android中binder学习总结

Binder学习总结

1、binder驱动和相应的接口函数

1.1、java开发者看binder驱动设备

binder驱动和linux驱动一样,以misc设备进行注册,作为虚拟字符设备,没有直接操作硬件,只是对设备内存进行操作。上述话语可能在网上能够搜索,但是笔者在学习过程中一直对这句话有一个思考:对于一个只是java开发者,甚至没有接触过驱动开发的人怎么去理解这句话。
经过对binder的学习现在的我对这句话的理解是:binder设备虽然只是一种虚拟字符设备,没有像键盘,鼠标这样的我们比较容易理解的实体物对应。但其实binder设备是有一定的实体物对应的那就是一块物理内存,binder驱动就是使用这一块物理内存来完成IPC的。这个解释有不正确的地方但是对于理解整个binder通信是有一定的好处的。比如binder中的binder_mmap方法的理解

1.2、binder驱动开放的接口函数

本篇文章对接口函数的说明:因为接口函数的代码相对于比较偏内核层,需要对linux有一定的了解。对于一个上层开发者直接阅读代码或许不是很明智的选择,因此以下对接口函数的解释仅限于理解层面并不涉及代码层面的解释。

先来一张图总体上理解以下binder的接口函数

init
open
mmap
ioctl

init函数最终会调用到内核中的binder_init函数。
binder_init方法在Android系统启动时进行调用,其主要工作是为了注册misc设备(misc设备属于linux中的杂项设备,其主设备号为10已经被限制,多个杂项设备通过此设备号进行区分),其中调用到的misc_register方法进行misc设备的注册。
个人认知中在linux世界里或许内存并不算是设备的一类,但是如果需要把一块物理内存当作一块设备来使用的话就需要虚拟化,从这个角度来看binder这个虚拟设备,其本质上是或许是一块物理内存。

open的主要作用是在内核binder设备内初始化一些结构体(如binder_proc)等信息,用于记录用户进程本次打开binder设备的一些信息;并返回一个文件描述符给用户进程,用户进程拿到这个文件描述符,后续与binder设备通信时便可以精确找到自己在binder设备中的映射。

mmap函数的主要功能是:首先在内核虚拟地址空间社情一块与用户虚拟内存相同大小的内存;然后再申请一块page整数倍大小的物理内存,最后将同一块物理内存分别映射到内核虚拟内存和用户虚拟内存。从而实现用户空间和内核空间的buffer同步的操作
理解上述这段话需要明白的一点是不论window操作系统还是linux操作系统,对于一个进程所使用的内存地址并不是真实的物理内存地址,而是由操作系统虚拟化出来的内存地址,该虚拟内存地址和物理内存地址有一定的映射关系,这个映射关系由操作系统维护。基于这一点去理解binder_mmap函数的功能就好理解了。内核空间和用户进程空间虽然在虚拟内存上相互独立但是在物理空间上确可以公用一块物理内存的,也就是说binder_mmap函数在操作系统的帮助下使内核地址和用户地址映射到同一块物理内存上,这样就实现了任何一方修改这一块物理内存都能够使另一方立即可见。

ioctl函数是真正实现IPC功能的函数,binder_init对于一个操作系统可能只会调用一次;binder_open、binder_mmap这两个函数对于一个进程来说可能只会被调用一次,这个调用频率在Android源代码中是有体现的。但是binder_ioctl函数的调用却是极为频繁的,每次IPC调用都是通过该函数实现的。

ioctl命令Binder Driver动作数据类型
BINDER_WRITE_READ在进程间接收发送BInder IPC数据struct binder_write_read
BINDER_SET_IDLE_TIME_OUT未使用int64_t
BINDER_SET_MAX_THREADS设定注册在binder driver中的binder线程的最大个数size_t
BINDER_SET_IDLE_PRIORITY未使用int
BINDER_SET_CONTEXT_MGR设定binder Driver的特殊节点int
BINDER_SET_THREAD_EXIT删除binder线程int
BINDER_SET_VERSION提供binder协议版本struct binder_version

上述表格来自于Android框架揭秘].金泰延等一书。这个表格内和binder_ioctl函数有关系的就是BINDER_WRITE_READ这个ioctl命令。需要注意的是它的数据类型是binder_write_read结构体,阅读Android相关源码时涉及到binder通信的相关代码都会出现这个结构体的身影。

2、Android中binder通信的通用规则

在binder_init、binder_open、binder_mmap以及最重要的binder_ioctl四个内核函数的支撑下,Android利用binder完成IPC通信的基石就已经奠基好了。在笔者阅读Android源码过程中,发现Android系统中使用binder通信是有一定规则的,首先先贴出来一张图:

Bp###::transact
BpBinder::transact
IPCThreadState::transact
客户端ioctl
BinderDriver
IPCThreadState::joinThreadPool
IPCThreadState::executeCommand
BBinder::transact
Bn###::某一方法

图中以Binder Driver为划分点,上方调用顺序为客户端发起IPC调用的流程,下方调用顺序为服务端接受IPC的流程(这个接收动作实际上是服务端主动去获取的,因为IPCThreadState::joinThreadPool 里面有一个死循环,该死循环会不断和binder driver交互来查看是否有新的请求过来)。

流程中Bp###和Bn###都来扩展了I###接口,笔者认为这是Android系统中binder通信的一个标准规范。Bp###位于客户端是服务端服务在客户端的代理,Bn###位于服务端是实现服务的具体实现(在服务端找寻Bn###不要只是局限于Bn###,因为有时候的具体实现可能是Bn###的某一子类。比如BnSurfaceComposerClient中具体实现并不在BnSurfaceComposerClient中而是在其子类Client中)。

BpBinder和BBinder也都扩展了IBinder接口,这个接口定义了binder通信的通用规则,目前我这边看到用到最多的是BpBinder的transact函数,客户端去执行binder通信,BBinder的onTransact函数用于服务端去分发处理客户端的请求。

至于IPCthreadstate这个类和ProcessState类,binder线程这个是有很大关联的。Android中每一个进程其实是有专门的binder线程由于去进行binder通信,这些binder线程基本已死循环的形式来保证自己不会消亡。
每一个进程都有且只有一个ProcessState实例,这个实例提供了去开启一个binder线程的方法如:startThreadPool和spawnPooledThread方法,第一个函数用于去将主线程作为一个binder线程去使用,spawnPooledThread可以将任意线程作为一个binder线程去使用,startThreadPool也是使用该方法来实现。

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

void ProcessState::spawnPooledThread(bool isMain)
{
    if (mThreadPoolStarted) {
        String8 name = makeBinderThreadName();
        ALOGV("Spawning new pooled thread, name=%s\n", name.string());
        sp<Thread> t = new PoolThread(isMain);
        t->run(name.string());
    }
}

spawnPooledThread方法中new PoolThread线程并开启了这个线程的运行,最终会调用到PoolThread线程的threadloop方法中,该方法调用了IPCThreadState的joinThreadPool方法进入死循环实时和binder driver交互取得新的请求

//以下为IPCThreadState::joinThreadPool的实现
void IPCThreadState::joinThreadPool(bool isMain)
{
    LOG_THREADPOOL("**** THREAD %p (PID %d) IS JOINING THE THREAD POOL\n", (void*)pthread_self(), getpid());

    mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
    
    // This thread may have been spawned by a thread that was in the background
    // scheduling group, so first we will make sure it is in the foreground
    // one to avoid performing an initial transaction in the background.
    set_sched_policy(mMyThreadId, SP_FOREGROUND);
        
    status_t result;
    do {
        processPendingDerefs();
        // now get the next command to be processed, waiting if necessary
        //实时和binder driver交互获取新的请求
        result = getAndExecuteCommand();

        if (result < NO_ERROR && result != TIMED_OUT && result != -ECONNREFUSED && result != -EBADF) {
            ALOGE("getAndExecuteCommand(fd=%d) returned unexpected error %d, aborting",
                  mProcess->mDriverFD, result);
            abort();
        }
        
        // Let this thread exit the thread pool if it is no longer
        // needed and it is not the main process thread.
        if(result == TIMED_OUT && !isMain) {
            break;
        }
    } while (result != -ECONNREFUSED && result != -EBADF);

    LOG_THREADPOOL("**** THREAD %p (PID %d) IS LEAVING THE THREAD POOL err=%p\n",
        (void*)pthread_self(), getpid(), (void*)result);
    
    mOut.writeInt32(BC_EXIT_LOOPER);
    talkWithDriver(false);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
千里马8年Android系统及应用开发经验,曾担任过美国unokiwi公司移动端技术总监兼架构师,对系统开发,性能优化,应用高级开发有深入的研究,Android开源定制ROM Lineage的贡献者之一,国内首家线下开辟培训Android Framework课程,拥有2年的Android系统培训经验。成为腾讯课堂专业负责android framework课程分享第一人,致力于提高国内android Framework水平Android Framework领域内是国内各大手机终端科技公司需要的人才,应用开发者都对Android系统充满着好奇,其binder是重之重,都说无binderAndroidbinde是Android系统的任督二脉。课程水平循序渐进,由级再到高级,满足各个层次水平的android开发者。1、灵活使用binder跨进程通信,在app端对它的任何api方法等使用自如2、可以单独分析android系统源码任何binder部分,分析再也没有难度3、掌握binder驱动本质原理,及对应binder驱动怎么进行跨进程通信,及内存等拷贝方式数据等4、对binder从上层的java app端一直到最底层的内核binder驱动,都可以顺利理通5、针对系统开发过程遇到的binder报错等分析方法,及binder bug案例学习6、针对面试官任何的binder问题都可以对答自如7、socket这种跨进程通信实战使用8、针对android源码使用的socket源码轻松掌握9、android系统源码最常见的socketpair双向跨进程通信10、使用socket实现一个可以让app执行shell命令的程序

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值