Android binder机制(native服务篇)

** 1、前言 **

Android系统使用binder机制进行进程间通信,为了更好地封装,使用户不用关心底层细节,binder机制变得相当复杂。

binder使用c/s架构,可类比socket通信,有服务端也有客户端 ,而binder驱动就相当于网络。

Paste_Image.png

本文以MediaPlayerService为例,阐述binder机制。

2、ServiceManager

ServiceManager,顾名思义,服务的管理者,所有的本地服务在启动的时候都会被保存在ServiceManager中,而用户可直接访问ServiceManager,获取所需要的服务。

ServiceManager运行在一个独立进程中,本地服务在启动时需要获取ServiceManager,将自身保存,这也是一个IPC过程。此时,ServiceManager作为服务端,而本地服务作为客户端。

以MediaPlayerService为例,查看MediaPlayerService是如何与ServiceManager通信,并将自身保存的呢?

查看MediaPlayerService.cpp的instantiate方法:

void MediaPlayerService::instantiate() {
defaultServiceManager()->addService(
        String16("media.player"), new MediaPlayerService());
}

查看defaultServiceManager源码:

sp<IServiceManager> defaultServiceManager()
{
if (gDefaultServiceManager != NULL) return gDefaultServiceManager;
{
    AutoMutex _l(gDefaultServiceManagerLock);
    while (gDefaultServiceManager == NULL) {
        gDefaultServiceManager = interface_cast<IServiceManager>(
            ProcessState::self()->getContextObject(NULL));
        if (gDefaultServiceManager == NULL)
            sleep(1);
    }
}
return gDefaultServiceManager;
}

现在MediaPlayerService向ServiceManager发出请求,存储服务,ServiceManager此时做为Server端,那么defaultServiceManager究竟返回的是什么对象呢?

3、痛苦的宏定义
继续查看ProcessState::self()->getContextObject(NULL)逻辑,ProcessState使用单例模式,确保一个进程中只有一个ProcessState对象。

sp<ProcessState> ProcessState::self()
{
Mutex::Autolock _l(gProcessMutex);
if (gProcess != NULL) {
    return gProcess;
}
gProcess = new ProcessState;
return gProcess;
}

ProcessState的构造方法中又做了什么呢?

ProcessState::ProcessState()
: mDriverFD(open_driver()) //初始化列表模式,打开binder驱动
, mVMStart(MAP_FAILED)
 。。。
{
if (mDriverFD >= 0) {
    // mmap the binder, providing a chunk of virtual address space to receive transactions.
    mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
}

ProcessState构造方法中,打开binder驱动,整篇都在讲binder,终于提到有个类与binder驱动交互了。

继续查看getContextObject方法。

sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
{
return getStrongProxyForHandle(0);
}

sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
sp<IBinder> result;
AutoMutex _l(mLock);
// 根据 handle值,在Vector 中查找
handle_entry* e = lookupHandleLocked(handle);
if (e != NULL) {
    IBinder* b = e->binder;
    //第一次查找,显示会得到空值
    if (b == NULL || !e->refs->attemptIncWeak(this)) {
        。。。
        // 构造一个BpBinder,最终返回它
        b = new BpBinder(handle); 
        e->binder = b;
        if (b) e->refs = b->getWeakRefs();
        result = b;
    } 
    。。。
}
return result;
}

回到前文的defaultServiceManager方法中,将返回值代入,得到

//注意,方法中传入的handle为0,所以BpBinder参数为0
gDefaultServiceManager = interface_cast<IServiceManager>(new BpBinder(0));

interface_cast,初看以为是强制类型转换的方法,以为自己太菜,这方法怎么没见过一样,左键点击下查看方法,才发现别有洞天。

inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
{
return INTERFACE::asInterface(obj);
}

原来是调用泛型类中的asInterface的方法,那么IServiceManager的asInterface的具体逻辑是什么呢?查看IServiceManager.h或者cpp文件查看,都找不到asInterface这个方法。但看到了下面一段声明:

// IServiceManager.h 中引用的
DECLARE_META_INTERFACE(ServiceManager);

点击一看,这个宏定义中正好定义了asInterface 方法。

#define DECLARE_META_INTERFACE(INTERFACE)                               \
static const android::String16 descriptor;                          \
static android::sp<I##INTERFACE> asInterface(                       \
        const android::sp<android::IBinder>& obj);                  \
virtual const android::String16& getInterfaceDescriptor() const;    \
I##INTERFACE();                                                     \
virtual ~I##INTERFACE();                                            \

但这只是方法定义,哪里实现的呢?已经在h文件中看到宏定义了,那么cpp文件中是否会有另外一定宏定义,来实现此方法呢? 答案是肯定的,在IServiceManager.cpp中果然看到一段宏定义

IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager");

点击查看宏定义具体内容:

#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME)                       \
const android::String16 I##INTERFACE::descriptor(NAME);             \
const android::String16&                                            \
        I##INTERFACE::getInterfaceDescriptor() const {              \
    return I##INTERFACE::descriptor;                                \
}                                                                   \
android::sp<I##INTERFACE> I##INTERFACE::asInterface(                \
        const android::sp<android::IBinder>& obj)                   \
{                                                                   \
    android::sp<I##INTERFACE> intr;                                 \
    if (obj != NULL) {                                              \
        intr = static_cast<I##INTERFACE*>(                          \
            obj->queryLocalInterface(                               \
                    I##INTERFACE::descriptor).get());               \
        if (intr == NULL) {                                         \
            intr = new Bp##INTERFACE(obj);                          \
        }                                                           \
    }                                                               \
    return intr;                                                    \
}                                                                   \
I##INTERFACE::I##INTERFACE() { }                                    \
I##INTERFACE::~I##INTERFACE() { }                                   \

将模板替换,可知asInterface方法代码为:

android::sp<IServiceManager> IServiceManager::asInterface(                \
        const android::sp<android::IBinder>& obj)                   \
{                                                                   \
    android::sp<IServiceManager> intr;                                 \
    if (obj != NULL) {                                              \
        intr = static_cast<IServiceManager*>(                          \
            obj->queryLocalInterface(                               \
                    IServiceManager::descriptor).get());               \
        if (intr == NULL) {                                         \
            intr = new BpServiceManager(obj);                          \
        }                                                           \
    }                                                               \
    return intr;                                                    \
}  

如果有看过java中的aidl文件,会发现这段代码和aidl被编译器自动处理过后的文件非常相似,如果client端和server端不在同一进程,那么必定走的流程是返回 BpServiceManager 。

BpServiceManager 类在哪呢?它定义在IServiceManager.cpp文件中。

一般native服务的接口定义在 I××Service.h 文件中,Bp××Service一般定义在I××Service.cpp文件当中

经过一系列的折腾,终于回到MediaPlayerService.cpp的instantiate方法了,代替下就是

void MediaPlayerService::instantiate() {
BpServiceManager->addService(String16("media.player"), new MediaPlayerService());
}

4、和Binder驱动正式通信

查看BpServiceManager的addService方法

virtual status_t addService(const String16& name, const sp<IBinder>& service,
        bool allowIsolated)
{
    Parcel data, reply;
    data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
    data.writeString16(name);
    data.writeStrongBinder(service);
    data.writeInt32(allowIsolated ? 1 : 0);
    status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
    return err == NO_ERROR ? reply.readExceptionCode() : err;
}

感觉这段代码非常眼熟,和java中的aidl差别不大,主要就是调用remote()->transact,和Binder驱动通信。问题来了,那remote()方法得到的是什么对象呢?

remote()方法返回的是mRemote对象,回溯上文所讲的asInterface方法,构造BpServiceManager对象,传入了一个BpBinder,查看BpServiceManager的构造函数,它最终引用父类BpRefBase的构造函数。

BpRefBase::BpRefBase(const sp<IBinder>& o)
: mRemote(o.get()), mRefs(NULL), mState(0)
{
   。。。。
}

于是得知addService方法中,其实是调用BpBinder的transact方法。

Paste_Image.png

根据在java中使用aidl的经验,调用transact方法后,最终肯定会调用到onTransact,最终调用到Server端的方法。

BpBinder的transact之后的调用流程如上,尤其关注IPCThreadState类。根据上图,IPCThreadState与Binder驱动通信,分别调用三个方法

  • writeTransactionData,向Binder驱动写数据
  • waitForResponse, 等待Binder驱动返回指令
  • executeCommand,执行Binder驱动的指令

目前和Binder驱动相关的代码已经有两个类了,一个是ProcessState,另一个是IPCThreadState,他们的关系如何,待会再说。

已经调用了onTransact方法,按理说,应该要调用Server端的方法了,可ServiceManager的server端代码在哪里呢?

ServiceManager是一个特殊的服务,因为它是服务的管理者,它在其它服务启动之前启动,它的server端代码在Service_manager.c类中,查看它的main方法。

int main(int argc, char **argv)
{
struct binder_state *bs;
//打开Binder驱动
bs = binder_open(128*1024);
//将自己设定为服务的管理者,管理者对象,整个android系统只有一个
if (binder_become_context_manager(bs)) {
    ALOGE("cannot become context manager (%s)\n", strerror(errno));
    return -1;
}
//开启循环,从binder中读取命令,执行命令
binder_loop(bs, svcmgr_handler);
}

再次回到onTransact方法,现在server端代码找到了,client端调用了addService,那么server端响应了什么操作呢?

Paste_Image.png

到目前为止,针对ServiceManager,从client端发起请求,到服务端响应请求的整个流程已经讲完了。

5、MediaPlayerService

根据ServiceManager的分析经验,一个本地服务至少涉及到以下几个类

  • I××Service.h,定义接口,引用宏定义等,从后文可知,它还会定义BN××Service类
  • I××Service.cpp,定义Bp××Service类,声明实现宏定义,从后文可知,它还会重写BN××Service类的onTransact方法
  • Service_manager.c,类似的看似不相关文件,打开binder驱动,初始化,循环读取binder驱动消息等
  • ××Service.cpp,I××Service.h中接口的具体实现者,ServiceManager中server端的具体逻辑实现在Service_manager.c中,但一般来说,会有这样的一个类,实现具体逻辑

MediaPlayerService服务的初始化在Main_mediaserver.cpp中,对应着ServiceManager系统的Service_manager.c,负责初始化,打开binder驱动,建议消息循环等等

int main(int argc __unused, char** argv)
{
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm = defaultServiceManager();
MediaPlayerService::instantiate();
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
}

然道先前的推测不对?main方法中并没有直接打开binder,也没有建立消息循环。联想到前文中的内容,与Binder驱动打交道的主要有两个类,一是ProcessState,另一个就是IPCThreadState。

在ProcessState的构造方法中,已经打开了binder驱动。

从代码上看 ProcessState::self()->startThreadPool(),好像是启动线程。


Paste_Image.png

查看IPCThreadState的joinThreadPool方法

void IPCThreadState::joinThreadPool(bool isMain)
{
    mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
    
    set_sched_policy(mMyThreadId, SP_FOREGROUND);
    status_t result;
    do {
        processPendingDerefs();
        // 从binder驱动中取出指令并执行
        result = getAndExecuteCommand();
    } while (result != -ECONNREFUSED && result != -EBADF);
    
    mOut.writeInt32(BC_EXIT_LOOPER);
    talkWithDriver(false);
}

此方法正好是建立消息死循环,与binder驱动沟通,取指令,执行指令等等。

但为什么此方法被调用两次呢?ProcessState的startThreadPool方法调用一次,而main方法最后又调用了一次,在工作线程中调用了,在主线程也调用了。是否可去掉其中之一,笔者不得而知。

IPCThreadState::self(),此方法又做了哪些工作呢?

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;
    }
    pthread_mutex_lock(&gTLSMutex);
    if (!gHaveTLS) {
        int key_create_value = pthread_key_create(&gTLS, threadDestructor);
        if (key_create_value != 0) {
            pthread_mutex_unlock(&gTLSMutex);
            return NULL;
        }
        gHaveTLS = true;
    }
    pthread_mutex_unlock(&gTLSMutex);
    goto restart;
}

TLS,线程局部存储,变量与线程相关,每个线程私有,不必考虑加锁问题,类似于java中的ThreadLocal类

由此可见,IPCThreadState,它是每个线程所独有的对象。
ProcessState是进程唯一的对象,这是两个非常有意思的单例。

这两个类都有与Binder驱动通信的逻辑,实质上是,IPCThreadState的构造方法中传入了ProcessState对象,IPCThreadState利用ProcessState与binder驱动通信

6、MediaPlayerService相关文件

IMediaPlayerService.h中定义了server端应该实现的接口,也定义了BnMediaPlayerService类

和前文中的IServiceManager.h一样

IMediaPlayerService.cpp中定义了BpMediaPlayerService类,也重写了BnMediaPlayerService的onTransact方法

IMediaPlayerService.h中定义的方法,在MediaPlayerService.cpp中具体实现。

7、总结

MediaPlayerService的client端与server端通信,和ServiceManager模块中类似,就不再复述。

此时再结合前言中的图片,如果每个类都做到心中有数了,那native服务的binder机制就基本了解了。

引用材料:
http://www.cnblogs.com/innost/archive/2011/01/09/1931456.html
http://blog.csdn.net/victorfreedom/article/details/43648309
http://blog.csdn.net/ykdsea/article/details/39271133

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,179评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,229评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,032评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,533评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,531评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,539评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,916评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,813评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,568评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,654评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,354评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,937评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,918评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,152评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,852评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,378评论 2 342

推荐阅读更多精彩内容