android binder机制分析 以MediaPlayer为例子

(一) 概述    

    android的binder机制提供一种进程间通信的方法,使不同一个进程可以以类
似远程过程调用的形式调用另一个进程所提供的功能。binder机制在Java环境和
C/C++环境都有提供。 

    android的代码中,与C/C++的binder包括一些类型和接口的定义和实现,相关
的代码在下面这几个文件中:

    frameworks/base/include/utils/IInterface.h
    frameworks/base/include/utils/Binder.h
    frameworks/base/include/utils/BpBinder.h
    frameworks/base/include/utils/IBinder
    frameworks/base/include/utils/Parcel.h
    frameworks/base/include/utils/IPCThreadState.h
    frameworks/base/include/utils/ProcessState.h
    frameworks/base/libs/utils/Binder.cpp
    frameworks/base/libs/utils/BpBinder.cpp
    frameworks/base/libs/utils/IInterface.cpp
    frameworks/base/libs/utils/IPCThreadState.cpp
    frameworks/base/libs/utils/Parcel.cpp
    frameworks/base/libs/utils/ProcessState.cpp
    为了了解这些类、接口之间的关系以及binder的实现机制,最好是结合一个例
子来进行研究。我选择的例子是android自带的媒体播放器的实现。其媒体播放器
的相关代码在下面这些目录中: 
   frameworks/base/include/media
   frameworks/base/media

   使用startUML的反向工程功能分析上面这些代码,并进行了一定的整理之后,
得到下面这幅类图(点击可查看原尺寸图片)。


android mediaplayer
<http://tupian.hudong.com/a3_78_82_14300001049604128936829816048_jpg.html>android
mediaplayer




  

   android的媒体播放功能分成两部分,一部分是媒体播放应用,一部分是媒体播
放服务(MediaServer,在系统启动时由init所启动,具可参考init.rc文件)。这
两部分分别跑在不同的进程中。媒体播放应用包括Java程序和部分C++代码,媒体
播放服务是C++代码,并且需要调用外部模块opencore来实现真正的媒体播放。媒
体播放应用和媒体播放服务之间需要通过binder机制来进行相互调用,这些调用包
括:

   (1)媒体播放应用向媒体播放服务发控制指令
   (2)媒体播放服务向媒体播放应用发事件通知(notify)

   媒体播放服务对外提供多个接口,在上面得图中包括其中的2个接
口:IMediaService和IMediaPlayer,IMediaplayer用于创建和管理播放实例,而
IMediaplayer接口则是播放接口,用于实现指定媒体文件的播放以及播放过程的控
制。

   上面的图中还有媒体播放应用向媒体播放服务提供的1个接
口:IMediaPlayerClient,用于接收notify。

   这些接口因为需要跨进程调用,因此需要用到binder机制。每个接口包括两部
分实现,一部分是接口功能的真正实现(BnInterface),这部分运行在接口提供
进程中;另一部分是接口的proxy(BpInterface),这部分运行在调用接口的进程
中。binder的作用就是让这两部分之间建立联系。下图是整个播放器的一个概要说
明。 

   

binder Ip
<http://tupian.hudong.com/a3_66_87_14300001049604128936872570001_jpg.html>binder
Ip



     媒体播放器比较复杂一些,总共实现了3个接口,不过要了解binder的机制,
只需要研究其中一个接口就足够了。在这里选择IMediaPlayerService接口来看一下。

     IMediaPlayerService接口包括六个功能函数:create(url)、create(fd)、
decode(url)、 decode(fd)、createMediaRecord()、
createMetadataRetriever()。在这里不介绍这些函数是做什么的,我们只关注如
何通过binder还提供这些函数接口。




(二) 接口定义

(1) 定义接口类


     首先定义IMediaPlayerService类,这是一个接口类(C++的术语应该叫纯虚
类)。该接口类定义在文件frameworks/base/include/media
/IMediaPlayerService.h。代码如下:


class IMediaPlayerService: public IInterface
{
public:
    DECLARE_META_INTERFACE(MediaPlayerService);

    virtual sp  createMediaRecorder(pid_t pid) = 0;
    virtual sp createMetadataRetriever(pid_t pid) = 0;
    virtual sp    create(pid_t pid, const sp& client, const char* url) = 0;
    virtual sp    create(pid_t pid, const sp& client, int fd, int64_t offset, int64_t length) = 0;

    virtual sp         decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat) = 0;

    virtual sp         decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat) = 0;

};

 
 
    可以看到,在这个接口类中定义了IMediaPlayerService需要提供的6个函数接
口,因为是接口类,所以定义为纯虚函数。需要注意这个接口类的名称有严格要
求,必须是以大写字母I开始。 
    重点关注在这些函数前面的一个宏定
义: DECLARE_META_INTERFACE(MediaPlayerService)。这个宏定义必须要有,其
中封装了实现binder所需要的一些类成员变量和成员函数通过这些成员函数可以为
一个binder实现创建proxy。这个宏定义在问价frameworks/base/include /utils
/IInterface.h里,在后面还会讲到。这个宏定义的参数必须是接口类的名称去除
字母I后剩下的部分。

    另外说明一下,可以看到接口类中所定义的函数的返回值都是sp的形式,看起
来有点怪异。sp是android中定义的一个模板类,用于实现智能指针功能。sp就是
IMediaPlayer的智能指针,可以简单地把它看成是标准C++中的指针定义
即 IMediaPlayer* 即可。

(2) 定义和实现binder类


    binder类包括两个,一个是接口实现类,一个接口代理类。接口代理类继承自
BpInterface,接口实现类继承自BnInterface。这两个基类都是模板类,封装了
binder的进程间通信机制,这样使用者无需关注底层通信实现细节。

    对于IMediaPlayerService接口,其binder接口实现类为
BnMediaPlayerService,接口代理类为 BpMediaPlayerService。需注意这两个类
的名称有严格要求,必须以Bn和Bp开头,并且后面的部分必须是前面所定义的接口
类的名称去除字母''''I’。比如前面所定义的接口类为IMediaPlayerService,去
除字母I后是MediaPlayerService,所以两个 binder类的名称分别是
BnMediaPlayerService和BpMediaPlayerService。为什么有这样的要求?原因就在
前面提到的宏定义DECLARE_META_INTERFACE()和另一个宏定义
IMPLEMENT_META_INTERFACE()里面。有兴趣的话可以去看一下,这两个宏定义都在
文件frameworks/base/include/utils/IInterface.h里。

    BpMediaPlayerService是一个最终实现类。定义并且实现在在文件
frameworks/base/media/libmidia /IMediaPlayerService.cpp中。在看
BpMediaPlayerService的代码之前,先看一下在 IMediaPlayerService.cpp文件的
开始部分的一个枚举定义:

enum {
    CREATE_URL = IBinder::FIRST_CALL_TRANSACTION,
    CREATE_FD,
    DECODE_URL,
    DECODE_FD,
    CREATE_MEDIA_RECORDER,
    CREATE_METADATA_RETRIEVER,
};

    这些6个枚举定义对应于IMediaPlayerService接口所提供的6个功能函数,可
以称为这些功能函数的功能代码,用于在进程之间进行RPC是标识需要调用哪个函
数。如果不想定义这些枚举值,在后面需要用到这些值的地方直接写上
1,2,3,4,5,6也是可以的,不过……一个合适的程序员会这么干吗?

    下面看一下BpMediaPlayerService的代码。

(3) BpMediaPlayerService代码分析


class BpMediaPlayerService: public BpInterface
{
public:
    BpMediaPlayerService(const sp& impl)
        : BpInterface(impl)
    {
    }

    virtual sp createMetadataRetriever(pid_t pid)
    {
        Parcel data, reply;
        data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());

        data.writeInt32(pid);
        remote()->transact(CREATE_METADATA_RETRIEVER, data, &reply);
        return interface_cast(reply.readStrongBinder());
    }

    virtual sp create(pid_t pid, const sp& client, const char* url)
    {
        Parcel data, reply;
        data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());

        data.writeInt32(pid);
        data.writeStrongBinder(client->asBinder());
        data.writeCString(url);
        remote()->transact(CREATE_URL, data, &reply);
        return interface_cast(reply.readStrongBinder());
    }

    virtual sp createMediaRecorder(pid_t pid)
    {
        Parcel data, reply;
        data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());

        data.writeInt32(pid);
        remote()->transact(CREATE_MEDIA_RECORDER, data, &reply);
        return interface_cast(reply.readStrongBinder());
    }

    virtual sp create(pid_t pid, const sp& client, int fd, int64_t offset, int64_t length)

    {
        Parcel data, reply;
        data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());

        data.writeInt32(pid);
        data.writeStrongBinder(client->asBinder());
        data.writeFileDescriptor(fd);
        data.writeInt64(offset);
        data.writeInt64(length);
        remote()->transact(CREATE_FD, data, &reply);
        return interface_cast(reply.readStrongBinder());
    }

    virtual sp decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)

    {
        Parcel data, reply;
        data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());

        data.writeCString(url);
        remote()->transact(DECODE_URL, data, &reply);
        *pSampleRate = uint32_t(reply.readInt32());
        *pNumChannels = reply.readInt32();
        *pFormat = reply.readInt32();
        return interface_cast(reply.readStrongBinder());
    }

    virtual sp decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)

    {
        Parcel data, reply;
        data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());

        data.writeFileDescriptor(fd);
        data.writeInt64(offset);
        data.writeInt64(length);
        remote()->transact(DECODE_FD, data, &reply);
        *pSampleRate = uint32_t(reply.readInt32());
        *pNumChannels = reply.readInt32();
        *pFormat = reply.readInt32();
        return interface_cast(reply.readStrongBinder());
    }
};
    首先可以看到,这个类继承自模板类BpInterface,指定类型为接口类
IMediaPlayerService。BpInterface模板类定义在文件IInterface.h。看一下
BpInterface的定义就可以发现,BpMediaPlayerService这样定义了以后,事实上
间接继承了IMediaPlayerService,从而可以提供IMediaPlayerService接口所定义
的接口函数。 BpMediaPlayerService需要实现这些接口函数。在一个简单的构造
函数之后,就是这些接口函数的实现。可以看到,所有的接口函数的实现方法都是
一致的,都是通过binder所提供的机制将参数仍给binder的实现类,并获取返回
值。这也就是这个类之所以成为代理类的原因。下面具体看一下一个接口函数。这
里选的是函数create(url)。

    virtual sp create(pid_t pid, const sp& client, const char* url)
    {
        Parcel data, reply;
        data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());

        data.writeInt32(pid);
        data.writeStrongBinder(client->asBinder());
        data.writeCString(url);
        remote()->transact(CREATE_URL, data, &reply);
        return interface_cast(reply.readStrongBinder());
    }

    这个接口函数的参数指定了一个URL,函数将为这个URL创建一个播放器实例用
于播放该URL。
    函数首先定义了两个局部变量data和reply,变量的类型都是Parcel。Parcel
是一个专为binder通信的数据传送而定义的类,该类提供了对多种类型的数据的封
装功能,同时提供多个数据读取和写入函数,用于多种类型的数据的写入和读取,
支持的数据类型既包括简单数据类型,也包括对象。这里定义的变量data是用于封
装create()函数调用所需要的输入参数,而reply则是用于封装调用的返回数据
(包括输出参数的值和函数返回值)。
    函数首先向data中写入各种数据。第一个写入的是接口的一个描述字符
串,binder的实现类中会用这个字符串来对接口做验证,防止调用错误。这个字符
串也可以不写,如果不写,在binder实现类中相应的也就不要做验证了。跟在描述
字符串后面写入的是该接口函数所需要的各种的输入参数。需要说明的是,Pacel
提供一种先入先出的数据存储方式,即数据的写入顺序和读取顺序必须严格一致,
否则将会出错。
    完成数据写入后,函数调用remote()->transact()用于完成binder通信。
transact()函数的第一个参数就是前面提到过的功能代码。transact()的功能是将
data中的数据传给binder的实现类,函数调用结束后,reply中将包含返回数据。
首先来看看 remote()成员函数。前面讲到过BpMediaPlayerService通过继承
BpInterface模板类间接继承了 IMediaPlayerService接口类,其实BpInterface类
是一个有两个父类的多重继承子类,另一个父类是 BpRefbase(frameworks/base
/include/utils/Binder.h)。remote()就是继承自BpRefBase 类的一个成员函
数,该函数返回BpRefBase类中定义的一个私有属性mRemote。mRemote是对IBinder
接口类的子类BpBinder 的一个对象的引用(参考前面的类关系图)。transact()
函数在IBinder接口类中定义(frameworks/base/include /utils/Binder.h),并
在BpBinder类中实现(frameworks/base/include/utils /BpBinder.h、
frameworks/base/libs/utils/BpBinder.cpp)。在transact()函数中将调
用 IPCThreadState类的transact()函数,并进而通过Lniux内核中的android共享
内存驱动来实现进程间通信。不过这些细节这里就不多说了。在这里BpBinder类对
象是一个关键,是实现Binder代理的核心之一。BpBinder类可以看成是一个通信
handle(类似于网络编程中的socket),用于实现进程间通信。接下来需要研究的
是这个BpBinder类对象(即mRemote成员变量的值)是从哪里来的。
    回过头来BpMediaPlayerService的构造函数(看前面的代码)。该构造函数的
参数是一个IBinder对象的引用。mRemote的值就是在这里传进来的这个对象。那么
这个对象又是怎么来的呢?要搞清楚这一点就需要找到创建BpMediaPlayerService
类的实例的代码,这个代码就就跟在该类的定义代码的下面。继续看
IMediaPlayerService.cpp文件,在BpMediaPlayerService类定义的后面,是下面
这样一行代码:


    IMPLEMENT_META_INTERFACE(MediaPlayerService, "android.hardware.IMediaPlayerService");



    这行代码调用了一个宏定义IMPLEMENT_META_INTERFACE()。这个宏定义与前面
提到过的 DECLARE_META_INTERFACE()相呼应。看名字就知
道,IMPLEMENT_META_INTERFACE()宏是对 DECLARE_META_INTERFACE()所定义的成
员函数的具体实现。这个宏的第一个参数与DECLARE_META_INTERFACE() 的参数需
完全一样,第二参数是接口的描述字符串(这个字符串前面也已经讲到过了)。描
述字符串不重要,重要的是宏里面定义的一个静态成员函数 asInterface()。
BpMediaPlayerService的类实例是在IMediaPlayerService的静态成员函
数 asInterface()中创建的,在IInterface.h中定义了一个内联函数
interface_cast(),对这个成员函数进行了封装。通过看代码容易知
道,BpMediaPlayerService的构造函数的参数是通过interface_cast()的参数传进
来的。
    好,下面就该看看这个interface_cast()是在哪里调用的,它的参数到底是什
么。找到frameworks/base/media /libmedia/mediaplayer.cpp文件,其中的
MediaPlayer::getMediaPlayerService()的实现代码:

const sp& MediaPlayer::getMediaPlayerService()
{
    Mutex::Autolock _l(sServiceLock);
    if (sMediaPlayerService.get() == 0) {
        sp sm = defaultServiceManager();
        sp binder;
        do {
            binder = sm->getService(String16("media.player"));
            if (binder != 0)
                break;
            LOGW("MediaPlayerService not published, waiting...");
            usleep(500000); // 0.5 s
        } while(true);
        if (sDeathNotifier == NULL) {
            sDeathNotifier = new DeathNotifier();
        }
        binder->linkToDeath(sDeathNotifier);
        sMediaPlayerService = interface_cast(binder);
    }
    LOGE_IF(sMediaPlayerService==0, "no MediaPlayerService!?");
    return sMediaPlayerService;
}

    看一下上面这段代码中的红色字体部分。结合前面的分析,可知BpBinder类的
对象实例是从android的服务管理器的getService()函数中获取,进一步追进去,
会发现下面这样一段代码:


{
        Parcel data, reply;
        data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());

        data.writeString16(name);
        remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply);
        return reply.readStrongBinder();
}


    Android的服务管理器是一个单独的进程,也向外提供接口。这段代码的含
义,是通过Android的服务管理器的接口代理,请求调用服务管理器
的 checkService()接口函数,查找指定的服务(上面就是查找media.player服
务),查找成功后返回一个BpBinder类的对象实例,用于供IMediaPlayerService
代理使用。这个对象BpBinder是在Parcel::readStrongBinder()函数里面创建的。
那么到底是怎么创建出来的呢?在这里没有必要追到ServiceManager的实现代码里
去,毕竟我们只是想知道BpBinder的对象是如何创建的,我们可以换一个例子来
看。回到前面的BpMediaPlayerService::create()函数的实现,是不是很眼熟。没
错,在那个函数里也创建了一个BpBinder类对象,那个对象是是给IMediaPlayer接
口代理使用的。虽然接口不同,但是创建原理是一样的。我们继续,下面该到
binder的另一个类——实现类的代码了。

(3) BnMediaPlayerService代码分析
    BnMediaPlayerService类的定义在文件frameworks/base/include
/media /IMediaPlayService.h,实现则与BpMediaPlayerService一样是在文件
frameworks/base/media /libmidia/IMediaPlayerService.cpp中。类定义的代码
如下:

class BnMediaPlayerService: public BnInterface
{
public:
    virtual status_t    onTransact( uint32_t code,
                                    const Parcel& data,
                                    Parcel* reply,
                                    uint32_t flags = 0);
};

    这个类继承自BnInterface模板类,约束类型为IMediaPlayerService。看一下
BnInterface模板类的定义(IInterface.h)就可以知道,BnMediaPlayerService
间接继承了IMediaPlayerService接口类。不过 BnInterface类并没有实现
IMediaPlayerService所定义的6个接口函数,因此BnInterface还是一个纯虚类。
这些接口需要在BnMediaPlayerService的子类中真正实现,这个子类就是
MediaPlayerService(frameworks/base /media/libmidiaservice
/MediaPlayerService.h,frameworks/base/media /libmidiaservice
/MediaPlayerService.cpp)。在BnMediaPlayerService的成员函数 onTransact()
中,需要调用这6个接口函数。BnMediaPlayerService中主要就是定义并实现了
onTransact()函数。当在代理那边调用了transact()函数后,这边的onTransact()
函数就会被调用。BnMediaPlayerService的实现代码如下:

#define CHECK_INTERFACE(interface, data, reply) /
        do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { /

            LOGW("Call incorrectly routed to " #interface); /
            return PERMISSION_DENIED; /
        } } while (0)

status_t BnMediaPlayerService::onTransact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    switch(code) {
        case CREATE_URL: {
            CHECK_INTERFACE(IMediaPlayerService, data, reply);
            pid_t pid = data.readInt32();
            sp client = interface_cast(data.readStrongBinder());
            const char* url = data.readCString();
            sp player = create(pid, client, url);
            reply->writeStrongBinder(player->asBinder());
            return NO_ERROR;
        } break;
        case CREATE_FD: {
            CHECK_INTERFACE(IMediaPlayerService, data, reply);
            pid_t pid = data.readInt32();
            sp client = interface_cast(data.readStrongBinder());
            int fd = dup(data.readFileDescriptor());
            int64_t offset = data.readInt64();
            int64_t length = data.readInt64();
            sp player = create(pid, client, fd, offset, length);
            reply->writeStrongBinder(player->asBinder());
            return NO_ERROR;
        } break;
        case DECODE_URL: {
            CHECK_INTERFACE(IMediaPlayerService, data, reply);
            const char* url = data.readCString();
            uint32_t sampleRate;
            int numChannels;
            int format;
            sp player = decode(url, &sampleRate, &numChannels, &format);
            reply->writeInt32(sampleRate);
            reply->writeInt32(numChannels);
            reply->writeInt32(format);
            reply->writeStrongBinder(player->asBinder());
            return NO_ERROR;
        } break;
        case DECODE_FD: {
            CHECK_INTERFACE(IMediaPlayerService, data, reply);
            int fd = dup(data.readFileDescriptor());
            int64_t offset = data.readInt64();
            int64_t length = data.readInt64();
            uint32_t sampleRate;
            int numChannels;
            int format;
            sp player = decode(fd, offset, length, &sampleRate, &numChannels, &format);

            reply->writeInt32(sampleRate);
            reply->writeInt32(numChannels);
            reply->writeInt32(format);
            reply->writeStrongBinder(player->asBinder());
            return NO_ERROR;
        } break;
        case CREATE_MEDIA_RECORDER: {
            CHECK_INTERFACE(IMediaPlayerService, data, reply);
            pid_t pid = data.readInt32();
            sp recorder = createMediaRecorder(pid);
            reply->writeStrongBinder(recorder->asBinder());
            return NO_ERROR;
        } break;
        case CREATE_METADATA_RETRIEVER: {
            CHECK_INTERFACE(IMediaPlayerService, data, reply);
            pid_t pid = data.readInt32();
            sp retriever = createMetadataRetriever(pid);
            reply->writeStrongBinder(retriever->asBinder());
            return NO_ERROR;
        } break;
        default:
            return BBinder::onTransact(code, data, reply, flags);
    }
}

    首先是一个宏定义CHECK_INTERFACE(),这个宏定义的作用是检查接口的描述
字符串,这个前面也提到过,不需细说。然后就是 onTrasact()函数的实现。这个
函数的结构也很简单,就是根据参数code的值分别执行不同的功能调用。code的取
值就是前面提到过的接口功能代码。函数的参数除了code,还包括Parcel类的两个
对象data和reply,分别用于传送输入参数和返回数据,与transact()函数的参数相
对应。还有一个参数flag在这里用不上,不讨论。对应我们前面所选择的接口函数
的例子create(url),看看这边对应的实现:

case CREATE_URL: {
     CHECK_INTERFACE(IMediaPlayerService, data, reply);
     pid_t pid = data.readInt32();
     sp client = interface_cast(data.readStrongBinder());
     const char* url = data.readCString();
     sp player = create(pid, client, url);
     reply->writeStrongBinder(player->asBinder());
     return NO_ERROR;
}

    首先是从data对象中依次取出各项输入参数,然后调用接口函数create()(将
在子类MediaPlayerService中实现),最后向reply中写入返回数据。这个函数返
回后,代理那边的transact()也会跟着返回。
    那么onTransact()函数是怎么被调用的呢?通过查看BnInterface模板类的定
义可以看到,这个类也是一个多重继承类,另一个父类
是 BBinder(frameworks/base/include/utils/Binder.h,frameworks/base
/libs /utils/Binder.cpp)。BBinder类继承自IBinder,也实现了transact()函
数,在这个函数中调用 onTransact()函数。而BBinder对象的transact()函数则是
在IPCThreadState类的 executeCommand()成员函数中调用的。这已经涉及到较底
层的实现,在这里不再多说。
    上面这部分代码还与前面提到过的BpBinder对象的创建有关系。看其中的红色
字体部分,通过create()函数调用会创建一个 IMediaPlayer接口类的子类的对
象,这个对象其实是MediaPlayerService::Client类(可以看一
下 MediaPlayerService的定义)的对象实例,而MediaPlayerService::Client类
是继承自 BnMediaPlayer类的,与BnMediaPlayerService类类似,BnMediaPlayer
其实也是一个binder实现类(是 BBinder的子类,进而也是IBinder的子类)。在
上述代码中,通过Parcel的writeStrongBinder()函数将这个对象写入 reply,而
在代理侧,通过Parcel的readStrongBinder()函数读取则可以得到一个BpBinder的
对象。至于类的具体创建过程已经封装在Parcel类的定义中,这里就不再多说了。

(4) 接口功能的真正实现
    到这里两个binder类就已经定义完了,下面就是IMediaPlayerService接口函
数的真正实现。前面已经说过这些函数在类 MediaPlayerService中实现。这个类
继承自BnMediaPlayerService,也间接地继承了 IMediaPlayerService接口类定义
的6个功能函数,只需要按照正常方式实现这6个功能函数即可,当然为了实现这6
个函数就需要其它一大堆的东西,不过这些具体的实现方法已经与binder机制无
关,不再多说。
   在MediaPlayerService类中定义了一个静态函数instantiate(),在这个函数中
创建MediaPlayerService的对象实例,并将这个对象注册到服务管理器中。这样需
要使用的时候就可以从服务管理器获取IMediaPlayerService的代理对象。这
个 instantiate()是在MediaServer程序的main()函数中调用的。 
void MediaPlayerService::instantiate() {
    defaultServiceManager()->addService(
            String16("media.player"), new MediaPlayerService());
}



(三) 总结一下
    说了这么多,总结一下。下图是binder机制的层次模型。


binder frame
<http://tupian.hudong.com/a0_84_87_14300001049604128936875859448_jpg.html>binder
frame

    如果一个服务需要通过binder机制对外提供跨进程的接口,需要做下面这些事
情。
    (1) 第一步,需要为这个接口定义一个继承自IInterface的接口类,假设叫
做IMyService。
    (2) 第二步,需要定义两个binder类,其中一个是代理类BpMyService,需
继承自BpInterface;另一个是实现类BnMyService,需继承自BnInterface。
    (3) 第三步,定义BnMyService的子类,这个子类可以是任何名字,比如就
叫MyService,在其中真正实现接口所提供的各个函数。
    (4) 第四步,创建MyService的实例,注册到服务管理器(如
IMediaPlayerService),也可以在其它接口的函数中创建(如上面的
IMediaPlayer)。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android Binder 机制Android 系统中的一种进程间通信(IPC)机制,用于在不同的进程之间传递数据和调用方法。它是 Android 系统中最重要的 IPC 机制之一,也是 Android 应用程序与系统服务进行通信的基础。 Binder 机制的工作原理是基于一个抽象的客户端-服务器模型。在 Binder 机制中,有三种角色:客户端、服务器和服务管理器。客户端和服务器在不同的进程中运行,而服务管理器运行在系统服务进程中。 当客户端需要与服务器通信时,它首先通过服务管理器获取服务器的引用。服务管理器通过一个名为 Binder 驱动的内核模块来实现进程间通信。客户端可以通过跨进程访问服务器对象来调用服务器上的方法,并将参数传递给服务器。服务器可以将结果返回给客户端。 Binder 机制的一个重要特性是它支持跨进程的对象引用。这意味着客户端可以获取服务器上的对象引用,并将其传递给其他进程中的客户端。通过这种方式,多个客户端可以共享服务器上的相同对象,并相互协作。 在 Android 应用程序中,开发者可以通过 AIDL(Android 接口定义语言)来定义客户端和服务器之间的接口。AIDL 可以生成一个 Java 接口和一个 C++ 接口,用于在客户端和服务器之间进行通信。 总之,Android Binder 机制Android 系统中用于进程间通信的核心技术之一。它提供了一种高效、灵活和安全的方式来在不同的进程之间传递数据和调用方法。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值