Android细说binder机制

Android深入浅出之Binder机制

一 说明
Android系统最常见最难搞明白的就是Binder了,很多很多的Service就是通过Binder机制来和客户端通讯交互的。所以搞明白Binder的话,在很大程度上就能理解程序运行的流程。
我们这里将以MediaService的例子来分析Binder的使用:

l ServiceManager,这是Android OS的整个服务的管理程序

l MediaService,这个程序里边注册了提供媒体播放的服务程序MediaPlayerService,我们最后只分析这个

l MediaPlayerClient,这个是与MediaPlayerService交互的客户端程序

下面先讲讲MediaService应用程序。

二 MediaService的诞生

MediaService是一个应用程序,虽然Android搞了七七八八的JAVA之类的东西,但是在本质上,它还是一个完整的Linux操作系统,也还没有牛到什么应用程序都是JAVA写。所以,MS(MediaService)就是一个和普通的C++应用程序一样的东西。

MediaService的源码文件在:framework\base\Media\MediaServer\Main_mediaserver.cpp中。让我们看看到底是个什么玩意儿!

int main(int argc, char** argv)

{

//FT,就这么简单??

//获得一个ProcessState实例

sp proc(ProcessState::self());

//得到一个ServiceManager对象

sp<IServiceManager> sm = defaultServiceManager();

MediaPlayerService::instantiate();//初始化MediaPlayerService服务

ProcessState::self()->startThreadPool();//看名字,启动Process的线程池?

IPCThreadState::self()->joinThreadPool();//将自己加入到刚才的线程池?

}

其中,我们只分析MediaPlayerService。

这么多疑问,看来我们只有一个个函数深入分析了。不过,这里先简单介绍下sp这个东西。

sp,究竟是smart pointer还是strong pointer呢?其实我后来发现不用太关注这个,就把它当做一个普通的指针看待,即sp======》IServiceManager*吧。sp是google搞出来的为了方便C/C++程序员管理指针的分配和释放的一套方法,类似JAVA的什么WeakReference之类的。我个人觉得,要是自己写程序的话,不用这个东西也成。

好了,以后的分析中,sp就看成是XXX*就可以了。

2.1 ProcessState
第一个调用的函数是ProcessState::self(),然后赋值给了proc变量,程序运行完,proc会自动delete内部的内容,所以就自动释放了先前分配的资源。

ProcessState位置在framework\base\libs\binder\ProcessState.cpp

sp ProcessState::self()

{

if (gProcess != NULL) return gProcess;---->第一次进来肯定不走这儿

AutoMutex _l(gProcessMutex);--->锁保护

if (gProcess == NULL) gProcess = new ProcessState;--->创建一个ProcessState对象

return gProcess;—>看见没,这里返回的是指针,但是函数返回的是sp,所以

//把sp看成是XXX*是可以的

}

再来看看ProcessState构造函数

//这个构造函数看来很重要

ProcessState::ProcessState()

: mDriverFD(open_driver())----->Android很多代码都是这么写的,稍不留神就没看见这里调用了一个很重要的函数

, mVMStart(MAP_FAILED)//映射内存的起始地址

, mManagesContexts(false)

, mBinderContextCheckFunc(NULL)

, mBinderContextUserData(NULL)

, mThreadPoolStarted(false)

, mThreadPoolSeq(1)

{

if (mDriverFD >= 0) {

//BIDNER_VM_SIZE定义为(1*1024*1024) - (4096 *2) 1M-8K

    mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE,

mDriverFD, 0);//这个需要你自己去man mmap的用法了,不过大概意思就是

//将fd映射为内存,这样内存的memcpy等操作就相当于write/read(fd)了

}

...

}

最讨厌这种在构造list中添加函数的写法了,常常疏忽某个变量的初始化是一个函数调用的结果。

open_driver,就是打开/dev/binder这个设备,这个是android在内核中搞的一个专门用于完成

进程间通讯而设置的一个虚拟的设备。BTW,说白了就是内核的提供的一个机制,这个和我们用socket加NET_LINK方式和内核通讯是一个道理。

static int open_driver()

{

int fd = open("/dev/binder", O_RDWR);//打开/dev/binder

if (fd >= 0) {

  ....

    size_t maxThreads = 15;

   //通过ioctl方式告诉内核,这个fd支持最大线程数是15个。

    result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);    }

return fd;

好了,到这里Process::self就分析完了,到底干什么了呢?

l 打开/dev/binder设备,这样的话就相当于和内核binder机制有了交互的通道

l 映射fd到内存,设备的fd传进去后,估计这块内存是和binder设备共享的

接下来,就到调用defaultServiceManager()地方了。

2.2 defaultServiceManager
defaultServiceManager位置在framework\base\libs\binder\IServiceManager.cpp中

sp defaultServiceManager()

{

if (gDefaultServiceManager != NULL) return gDefaultServiceManager;

//又是一个单例,设计模式中叫 singleton。

{

    AutoMutex _l(gDefaultServiceManagerLock);

    if (gDefaultServiceManager == NULL) {

//真正的gDefaultServiceManager是在这里创建的喔

        gDefaultServiceManager = interface_cast<IServiceManager>(

            ProcessState::self()->getContextObject(NULL));

    }

}

return gDefaultServiceManager;

}

—–》

gDefaultServiceManager = interface_cast(

            ProcessState::self()->getContextObject(NULL));

ProcessState::self,肯定返回的是刚才创建的gProcess,然后调用它的getContextObject,注意,传进去的是NULL,即0

//回到ProcessState类,

sp ProcessState::getContextObject(const sp& caller)

{

if (supportsProcesses()) {//该函数根据打开设备是否成功来判断是否支持process,

//在真机上肯定走这个

    return getStrongProxyForHandle(0);//注意,这里传入0

}

}

—-》进入到getStrongProxyForHandle,函数名字怪怪的,经常严重阻碍大脑运转

//注意这个参数的命名,handle。搞过windows的应该比较熟悉这个名字,这是对

//资源的一种标示,其实说白了就是某个数据结构,保存在数组中,然后handle是它在这个数组中的索引。—>就是这么一个玩意儿

sp ProcessState::getStrongProxyForHandle(int32_t handle)

{

sp<IBinder> result;

AutoMutex _l(mLock);

handle_entry* e = lookupHandleLocked(handle);–》哈哈,果然,从数组中查找对应

索引的资源,lookupHandleLocked这个就不说了,内部会返回一个handle_entry

下面是 handle_entry 的结构

/*

struct handle_entry {

            IBinder* binder;--->Binder

            RefBase::weakref_type* refs;-->不知道是什么,不影响.

        };

*/

if (e != NULL) {

    IBinder* b = e->binder; -->第一次进来,肯定为空

    if (b == NULL || !e->refs->attemptIncWeak(this)) {

        b = new BpBinder(handle); --->看见了吧,创建了一个新的BpBinder

        e->binder = b;

        result = b;

    }....

}

return result; 返回刚才创建的BpBinder。

}

//到这里,是不是有点乱了?对,当人脑分析的函数调用太深的时候,就容易忘记。

我们是从gDefaultServiceManager = interface_cast(

            ProcessState::self()->getContextObject(NULL));

开始搞的,现在,这个函数调用将变成

gDefaultServiceManager = interface_cast(new BpBinder(0));

BpBinder又是个什么玩意儿?Android名字起得太眼花缭乱了。

因为还没介绍Binder机制的大架构,所以这里介绍BpBinder不合适,但是又讲到BpBinder了,不介绍Binder架构似乎又说不清楚….,sigh!

恩,还是继续把层层深入的函数调用栈化繁为简吧,至少大脑还可以工作。先看看BpBinder的构造函数把。

2.3 BpBinder
BpBinder位置在framework\base\libs\binder\BpBinder.cpp中。

BpBinder::BpBinder(int32_t handle)

: mHandle(handle) //注意,接上述内容,这里调用的时候传入的是0

, mAlive(1)

, mObitsSent(0)

, mObituaries(NULL)

{

IPCThreadState::self()->incWeakHandle(handle);//FT,竟然到IPCThreadState::self()

}

这里一块说说吧,IPCThreadState::self估计怎么着又是一个singleton吧?

//该文件位置在framework\base\libs\binder\IPCThreadState.cpp

IPCThreadState* IPCThreadState::self()

{

if (gHaveTLS) {//第一次进来为false

restart:

    const pthread_key_t k = gTLS;

//TLS是Thread Local Storage的意思,不懂得自己去google下它的作用吧。这里只需要

//知道这种空间每个线程有一个,而且线程间不共享这些空间,好处是?我就不用去搞什么

//同步了。在这个线程,我就用这个线程的东西,反正别的线程获取不到其他线程TLS中的数据。===》这句话有漏洞,钻牛角尖的明白大概意思就可以了。

//从线程本地存储空间中获得保存在其中的IPCThreadState对象

//这段代码写法很晦涩,看见没,只有pthread_getspecific,那么肯定有地方调用

// pthread_setspecific。

    IPCThreadState* st = (IPCThreadState*)pthread_getspecific(k);

    if (st) return st;

    return new IPCThreadState;//new一个对象,

}



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; //我FT,其实goto没有我们说得那样卑鄙,汇编代码很多跳转语句的。

//关键是要用好。

}

//这里是构造函数,在构造函数里边pthread_setspecific

IPCThreadState::IPCThreadState()

: mProcess(ProcessState::self()), mMyThreadId(androidGetTid())
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
千里马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命令的程序

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值