Android的Binder机制浅析

Android的Binder机制浅析

1. 引言 

一般实际的软件系统中进程间通信(IPC)的实现方法有命名管道(named pipe),共享内存(shared memory),消息队列(message queue),Socket等方法。在Android的框架(Framework)中,以Binder作为框架内进程间(通常如服务和客户间)通信的主要实现手段。这可能是出于效率和软件架构考虑。Binder通信的底层基础是Binder设备,本文通过一些实例简要介绍基于Binder通信的流程,由于整个机制,尤其是驱动和一些数据封装部分相当复杂,本文也仅仅关注了其主体的流程,难免有疏漏和错误。 

2. Binder相关模块及其流程 

Binder通信主要涉及以下文件: 
进程状态对象: 
include/utils/ProcessState.h, lib/utils/ProcessState.cpp 
IPC通信机制和状态: 
include/utils/IPCThreadState.h, lib/utils/ProcessState.cpp 
Binder基础类: 
include/utils/Binder.h,(以及一些派生类等) 
(本文不加说明,相对目录均从/frameworks/base出发) 

设备驱动模块: 
Binder驱动模块位于Android根目录下/kernel/drivers/misc/binder.c中。 

2.1 主要模块概览 

图1显示了Framework中模块。其中XXX表示某具体应用。例如对Surface,其接口就是ISurface,本地调用端就是BpSurface,实现端就是BnSurface;对ServiceManager其接口就是IServiceManager,本地调用端就是BpServiceManager,实现端就是BnServiceManager。

clip_image002


图1 IPC-Binder相关对象继承关系

接口IXXX规定了这个应用需要实现的一些方法,例如ISurface中就定义了以下方法:

方法名说明
registerBuffers注册Buffer
postBuffer输送Buffer
unregisterBuffers注销Buffer
createOverlay创建叠层

以Surface应用为例,远端实现侧(进程)是一个Surface操作的具体实现。而在另一个具体的进程中只要通过创建和使用BpSurface,就能够调用这个远端进程的功能。 
于是BpXXX,在这里即BpSurface,由于继承了ISurface,必须也实现这些方法。而通常BpXXX是本地调用远端具体实现的入口,因此在这其中通常是启动IPC,传入和传出数据和参数的过程,这其中mRemote(BpBinder对象)是媒介,详见后续讨论。 
而BnXXX,即BnSurface,同样也继承了IServiceManager,也实现这些方法。而BnXXX(或其派生类),必须真正实现这些方法的具体工作,因为它是被BpXXX调用的。

又如SurfaceFlingerClient,其接口ISurfaceFlingerClient定义如下方法:

方法名说明
getControlBlocks获得控制块
createSurface创建一个Surface对象(Bp, Bn侧)
destroySurface销毁一个Surface对象
setState设置状态

而媒体播放器服务MediaPlayerService,其接口IMediaPlayerService定义如下方法:

方法名说明
createMediaRecorer创建一个媒体录制器(MediaRecorder)
createMetadataRetriever创建一个元数据读取器(MetadataRetriever)
create创建一个媒体播放器(MediaPlayer)
decode解码一个流

同样服务管理模块ServiceManager也是一个基于Binder的应用,接口IServiceManager定义了如下方法:

方法名说明
getService获得一个服务
checkService查询服务
addService添加一个服务
listServices列举服务


2.2 Binder初始化 

由于Binder的基础是Binder设备,因此设备的启动和配置是首要操作。 
首先一个是Binder处理进程,它是android启动后第一个运行的binder相关程序。以下代码主要在cmds/serviceManager/binder.c中。以下是代码分析片段:

   1: int main(int argc, char **argv)
   2: {
   3:     struct binder_state *bs;
   4:     void *svcmgr = BINDER_SERVICE_MANAGER;    //一个NULL指针
   5:  
   6:     bs = binder_open(mapsize = 128*1024)
   7:     {
   8:
   9:         bs->fd = open("/dev/binder", O_RDWR);
  10:
  11:         bs->mapsize = mapsize;
  12:         bs->mapped = mmap(NULL, mpasize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
  13:
  14:     }
  15:  
  16:     binder_become_context_manager(bs)
  17:     {
  18:         // 将本进程在内核中注册为context manager
  19:         ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
  20:     }
  21:  
  22:     svcmgr_handle = svcmgr;
  23:     binder_loop(bs, svcmgr_handler)    // binder消息分发的关键循环
  24:     {
  25:
  26:         for(;;) {
  27:
  28:             // 一般阻塞再此,直到有消息送达(阻塞点1),详见激活点1
  29:             ioctl(bs->fd, BINDER_WRITE_READ, &bwr)
  30:             {
  31:
  32:                 binder_thread_write(…) { …}
  33:                 binder_thread_read(…)
  34:                 {
  35:                     …激活后,相应处理中会在ptr所指buffer中将cmd设置为
  36:                     BR_TRANSACTION
  37:                 }
  38:
  39:             }
  40:             
  41:             // 解析消息
  42:             binder_parse(bs, bio = 0, ptr=readbuf, size = bwr.read_consumed, 
  43:                         func = svcmgr_handler)
  44:             {
  45:                 while (解析readbuf未完)
  46:                 {
  47:                     cmd = *ptr++;
  48:                     switch(cmd)
  49:                     {
  50:
  51:                     case BR_TRANSACTION:
  52:                         func {=svcmgr_handler}(bs, txn, &msg, &reply)
  53:                         {
  54:
  55:                             switch(txn->code)
  56:                             {
  57:                             case SVC_MGR_GET_SERVICE: …
  58:                             case SVC_MGR_CHECK_SERVICE: …
  59:
  60:                             }
  61:
  62:                         }
  63:                         binder_send_reply(bs, &reply, txn->data, res)
  64:                         {
  65:                             data= …
  66:                             binder_write(bs, &data, sizeof(data))
  67:                             {
  68:                                 ioctl(bs->fd, BINDER_WRITE_READ, &bwr)
  69:                             }
  70:                         }
  71:                     }
  72:                 }
  73:             }
  74:         }
  75:     }
  76:     return 0;
  77: }

2.3 Runtime初始化 

以下的服务进程和2.2介绍的类似,也是实现了ServiceManager的接口功能,只是它是用C++实现的,并且其本身也做成了Binder类型。 
因此,它可能是在上述2.2初始化之后最先加入的服务,而此后它将服务于维护其他服务。同样它也注册成Context Manager,这样在客户侧调用时无需制定具体的对象句柄。 
以下程序位于cmds/runtime/main_runtime.cpp。

   1: int main(…)
   2: {
   3:
   4:     boot_init()
   5:     {
   6:         proc = ProcessState::self();
   7:         proc->becomeContextManager(contextChecker, NULL)
   8:         {
   9:
  10:             // 本进程变为Context Manager,接受后续的Binder处理
  11:             ioctl(mDriverFD, BINDER_SET_CONTEXT_MGR, &dummy);
  12:
  13:         }
  14:  
  15:         sm = new BServiceManager;
  16:  
  17:         proc->setContextObject(IBinder object = sm)
  18:         {
  19:             setContextObject(sm, "default")
  20:             {
  21:                 mContexts.add("default", sm)
  22:                 {
  23:                     装入映射表mContexts中…
  24:                 }
  25:             }
  26:         }
  27:
  28:         run(…)
  29:         {
  30:
  31:             IPCThreadState::self()->joinThreadPool()
  32:             {
  33:                 等待消息,过程类似2.7中的讨论 
  34:             }
  35:         }
  36:     }
  37:
  38: }

BServiceManager实现BnServiceManager,由于ServiceManager服务程序作为ContextManager,因此后续在defaultServiceManager()上进行IServiceManager调用(如调用getService())都将定向到这个对象,而BServiceManager则维护了系统中的所有服务。 

2.4 Bp对象的创建 

Bp相关类型在framework中通过宏定义实现。这个宏定义在include/utils/IInterface.h中以DECLARE_META_INTERFACE和IMPLEMENT_META_INTERFACE命名。在相关的类定义中加入,例如在BpSurface这个例子中,它在ISurface.cpp中出现。

   1: sp BpSurfaceFlingerClient::createSurface(..)
   2: {
   3:
   4:     data上设置参数
   5:     mRemote->transact(CREATE_SURFACE, data, &reply)
   6:     {
   7:         … IPC调用到Bn侧功能并返回
   8:     }
   9:
  10:     sp binder = reply.readStrongBinder()
  11:     {
  12:         unflatten_binder(proc=ProcessState::self(), *this, sp* out = &val)
  13:         {
  14:             // 从in中取出flat_binder_object
  15:             flat_binder_object *flat = in.readObject(false);
  16:             if (flat)
  17:             {
  18:                 switch(flat->type)
  19:                 {
  20:
  21:                 case BINDER_TYPE_HANDLE:    // 本节注释1
  22:                     *out = proc->getStrongProxyForHandle(flat->handle)
  23:                     /* ProcessState:: getStrongProxyForHandle() */
  24:                     {
  25:                         // 查表获得一个表项,若首次则创建一个表项
  26:                         e = lookupHandleLocked(handle);
  27:                         if (e != NULL) {
  28:                             IBinder * b = e->binder;
  29:                             if (b == NULL || …)
  30:                             {    // 初次e->binder为空
  31:                                 e->binder = b = new BpBinder(handle)
  32:                                 { mHandle = handle; }
  33:
  34:                                 result = b;
  35:                             }
  36:                         }
  37:                         return result;
  38:                     }
  39:                     return finish_unflatten_binder(NULL, *flat, in);
  40:                 }
  41:             }
  42:         }
  43:         return val;
  44:     }
  45:     return interface_cast(binder)        // 上述宏定义的展开
  46:     {
  47:         return sp ISurface::asInterface(binder)
  48:         {
  49:             sp intr;
  50:             if (binder != NULL)
  51:             {
  52:
  53:                 intr = new BpSurface(binder)
  54:                 {
  55:                     基类创建:BpRefBase(binder)
  56:                     {
  57:                         mRemote = binder.get();    // 即刚创建的BpBinder
  58:                     }
  59:                 }
  60:             }
  61:         }
  62:     }
  63: }

可见BpSurfaceFlingerClient的作用之一是创建BpSurface对象。两者都在客户端(同一进程中)。 

----- 
【注释1】 在binder_transaction传递(ioctl在BINDER_WRITE_READ的BC_REPLY返回时,详见后续章节)中会将扁平处理的binder信息flat_binder_object中的类型从BINDER_TYPE_BINDER转换为BINDER_TYPE_HANDLE,而具体的handle是从底层对象注册用的红黑树上取出的唯一handle号,这样Bp侧用这个handle号和Bn侧的具体对象对应。

2.5 Bn对象的创建 

而在Bn侧BnSurfaceFlingerClient::onTransact处理上述mRemote->transact的过程:

   1: BnSurfaceFlingerClient::onTransact(…)
   2: {
   3:
   4:     switch(code) {
   5:     case CREATE_SURFACE:
   6:         从data上获取参数
   7:         sp s = BClient::createSurface(…)
   8:         {
   9:
  10:             创建一个Bn侧的ISurface实体对象s
  11:             (BnSurface类型,具体如LayerBuffer::SurfaceBuffer)
  12:
  13:             sBinder = s->IInterface::asBinder()
  14:             {
  15:                 BnInterface::onAsBinder()
  16:                 {
  17:                     return this;
  18:                 }
  19:             }
  20:             reply->writeStrongBinder(sBinder)
  21:             {
  22:                 flatten_binder(ProcessState::self(), binder= sBinder, out = this = reply)
  23:                 {
  24:                     flat_binder_object obj;
  25:                     obj.flags = …
  26:                     if (sBinder!= NULL)
  27:                     {
  28:                         local = binder->localBinder() { return this; }
  29:                         if (!local)…
  30:                         else
  31:                         {
  32:                             obj.type = BINDER_TYPE_BINDER;
  33:                             obj.binder = local->getWeakRefs();
  34:                             obj.cookie = local;    // 这个在后续访问操作使用
  35:                         }
  36:                     }
  37:                     … 其他分支略
  38:  
  39:                     return finish_flatten_binder(sBinder, obj, out)
  40:                     {
  41:                         out->writeObject(obj, nullMetaData = false)
  42:                         {
  43:                             …将obj数据写到out这个Parcel对象中
  44:                         }
  45:                     }
  46:                 }
  47:             }
  48:             // 此后reply这个Parcel将通过IPC传回客户端
  49:         }
  50:
  51:     }
  52: }

上述客户端和远端代码基本展示了Surface的创建过程。Bp和Bn侧的Surface创建完成后才有后续Surface的具体运作。 

2.6 BpSurface运作 

以前面提到的ISurface上的postBuffer接口的工作为例。这部分将深一些到IPC 事务(transaction)作业内部。其实前一节的Surface的创建过程已经调用了ISurfaceFlingerClient::createSurface接口,已经走了一遍类似的transaction事务流程,而前一节主要以BpSurface和BnSurface为例介绍在IPC流程的前提——两侧的建立为目的,在这里再对此后的事务操作进行详细介绍。 
从BpSurface出发:

   1: void BpSurface::postBuffer(offset)
   2: {
   3:     data.writeInterfacetoken(ISurface::getInterfaceDescriptor());    // ISurface接口描述符
   4:     data.writeInt32(offset);
   5:     mRemote->transact(code =POST_BUFFER, data, reply = &reply, 
   6:                       flags = IBinder::FLAG_ONEWAY)    // FLAG_ONEWAY=1
   7:     (mRemote即刚才建立的BpBinder对象,即BpBinder::transact(..))
   8:     {
   9:
  10:         IPCThreadState::self()->transact(handle = mHandle, code, data, reply, flags)
  11:         {    // handle是对应Bn侧Surface对象的有效值
  12:
  13:             writeTransactionData(cmd = BC_TRANSACTION, flags, handle, 
  14:                                  code, data, NULL)
  15:             {
  16:                 binder_transaction_data tr;
  17:                 tr.target.handle = handle; 
  18:                 tr.code = code; tr.flags = flags;
  19:                 ...
  20:                 mOut.writeInt32(cmd)
  21:                 mOut.write(&tr, sizeof(tr));
  22:
  23:             }
  24:
  25:             waitForResponse(reply = NULL, acquireResult = NULL)    // 不需要返回值
  26:             {
  27:                 while(1)
  28:                 {
  29:                     talkWithDriver()
  30:                     {
  31:
  32:                         ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr)
  33:
  34:                     }
  35:                     … 处理返回值
  36:                 }
  37:             }
  38:         }
  39:
  40:     }
  41: }

上述ioctl将调用请求做成通过Binder发送到远端。其过程在后续章节介绍。

2.7 Binder驱动概要 

在/kernel/drivers/misc/binder.c的Binder设备驱动中,定义了以下函数,它在内核中处理上述ioctl调用,完成Binder的功能。

   1: static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
   2: {
   3:
   4:     // 以下将本函数调用者进程挂起(如上述BpSurface所在进程),直到处理完返回
   5:     wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
   6:  
   7:     // 进程私有数据
   8:     binder_proc proc = filp->private_data;    
   9:     // 获得调用者进程的线程池数据结构
  10:     binder_thread *thread = binder_get_thread(proc);
  11:
  12:     switch(cmd)
  13:     {
  14:     case BINDER_WRITE_READ:
  15:
  16:         // 从用户空间将bind_write_read参数复制到bwr
  17:         copy_from_user(&bwr, ubuf, sizeof(bwr);
  18:
  19:         binder_thread_write(proc, thread, bwr.write_buffer, bwr.write_size,
  20:                             bwr.write_consumed)
  21:         {
  22:             while (处理bwr.write_buffer未完成)
  23:             {
  24:                 // 从用户空间获取cmd数据到内核空间
  25:                 get_user(cmd, (uint32_t __user *)ptr);
  26:
  27:                 switch(cmd)
  28:                 {
  29:
  30:                 case BC_TRANSACTION: case BC_REPLY: 
  31:                     // 从用户空间得到binder_transaction_data数据
  32:                     copy_from_user(&tr, ptr, sizeof(tr));
  33:
  34:                     binder_transaction(proc, thread, tr=&tr, 
  35:                         reply=(cmd==BC_REPLY)=false)
  36:                     {
  37:
  38:                         if (reply) 
  39:                         {    // 是回复
  40:
  41:                         }
  42:                         else
  43:                         {    // 是正向请求
  44:                             if (tr->target.handle)
  45:                             {    // 从红黑树中获得对应的节点
  46:                                 ref = binder_get_ref(proc, tr->target.handle);
  47:
  48:                                 target_node = ref->node;
  49:                             }
  50:                             else
  51:                             // 找到节点对应的服务进程
  52:                             target_proc = target_node->proc;    
  53:
  54:                         }
  55:                         if (target_thread) …
  56:                         else
  57:                         {
  58:                             target_list = &target_proc->todo;
  59:                             target_wait = &target_proc->wait;
  60:                         }
  61:
  62:                         for(遍历其中的flat objects)
  63:                         {
  64:                             …在postBuffer这个例子中忽略
  65:                             …在createSurface中它将消息内含flat object进行处理
  66:                             … 以实现两侧物件BINDER和HANDLE类型转换,
  67:                             … 即完成2.4的注释1中的过程:
  68:                             switch(fp->type)
  69:                             {
  70:
  71:                             case BINDER_TYPE_BINDER: 
  72:
  73:                                 node=binder_new_node(proc, 
  74:                                 ptr = fp->binder, cookie = fp->cookie)
  75:                                 {
  76:
  77:                                     node->proc = proc;    
  78:                                     // 这个进程就是BnSurfaceFlingerClient和
  79:                                     // BnSurface所在进程
  80:                                     node->ptr = ptr;
  81:                                     node->cookie = cookie;
  82:
  83:                                 }
  84:  
  85:
  86:                                 binder_get_ref_for_node(target_proc, node);
  87:
  88:                                 fp->type = BINDER_TYPE_HANDLE;
  89:
  90:                             }
  91:                         }
  92:
  93:                         // 激活点1:
  94:                         // 唤醒进程(见“阻塞点2”)
  95:                         // (对于在ServiceManager阶段会激活service_manager的“阻塞点1”)
  96:                         wake_up_interruptible (target_wait);
  97:                     }    // binder_transaction
  98:                 }
  99:             }    // binder_thread_write
 100:
 101:             binder_thread_read(…)
 102:             {
 103:                 … 读取数据
 104:                 … 处理
 105:                 if (t->buffer->target_node) {
 106:                     
 107:                     tr.target.ptr = target_node->ptr;
 108:                     tr.cookie = target_node->cookie;    //本地对象指针
 109:                     … 相应处理中会在ptr所指buffer中将cmd设置为
 110:                     BR_TRANSACTION
 111:                 }
 112:             }
 113:             if (读得数据) 
 114:                 wake_up_interruptible(&proc->wait); //激活等数据的用户进程
 115:         }
 116:
 117:         // 反馈给用户空间
 118:         copy_to_usr(ubuf, &bwr, sizeof(bwr));
 119:     }
 120: }

2.8 IPC处理和监听线程 

以下Surface相关服务的进程入口(cmds/surfaceflinger/main_surfaceflinger.cpp):

   1: int main(…)
   2: {
   3:
   4:     SurfaceFlinger::instantiate()
   5:     {    /* 实例化SurfaceFlinger服务 */
   6:         sm = defaultServiceManager()
   7:         {
   8:             if (gDefaultServiceManager != NULL) return gDefaultServiceManager;
   9:
  10:             // 在当前进程中首次调用
  11:             
  12:             co = ProcessState::self()->getContextObject(NULL)
  13:             {
  14:                 if (supportsProcess()) {    /* Android支持此分支 */
  15:                     return getStrongProxyForHandle(0)
  16:                     {
  17:                         具体流程类似2.4节介绍,生成一个新的BpBinder对象
  18:                         (ServiceManager的实际对象作为Context,功能实体在启
  19:                         动时已经产生,即2.3介绍的BServiceManager,所以此
  20:                         处不在需要生成Bn对象)
  21:                     }
  22:                 } else
  23:             }
  24:             gDefaultServiceManager = interaface_cast(co)
  25:             {
  26:                 …具体流程类似2.4节介绍,新建一个BpServiceManager对象
  27:                   上述BpBinder对象作为其mRemote
  28:             }
  29:             return gDefaultServiceManager;
  30:         }
  31:         sm->addService()
  32:         {
  33:             远程调用,完成服务(SurfaceFlinger)的加载
  34:         }
  35:     }
  36:     
  37:     …    其他服务创建 …
  38:     ProcessState::self()->startThreadPool()
  39:     {
  40:
  41:         spawnPoolThread(true)
  42:         {
  43:             创建线程运行IPCThreadState::self()->joinThreadPool(true)
  44:         }
  45:     }
  46:  
  47:     IPCThreadState::self()->joinThreadPool()
  48:     {
  49:
  50:         do {
  51:             …处理输入信息
  52:             talkWithDriver()
  53:             { 
  54:                 通过ioctl和binder设备交换信息(见前几节介绍),
  55:                 数据未到时挂起(阻塞点2)
  56:             }
  57:
  58:             cmd = mIn.readInt32();
  59:             executeCommand(cmd)
  60:             {
  61:                 switch(cmd)
  62:                 {
  63:
  64:                 case BR_TRANSACTION:
  65:                     binder_transaction_data tr;
  66:                     mIn.Read(&tr, sizeof(tr));
  67:
  68:                     if (tr.target.ptr)
  69:                     {
  70:                         sp b = ((BBinder*)tr.cookie;    // 本地对象指针
  71:                         b->transact(tr.code, buffer, &reply, 0)
  72:                         {
  73:                             BnSurface:: onTransact(…)
  74:                             {
  75:                                 switch(code)
  76:                                 {
  77:
  78:                                     case POST_BUFFER:
  79:
  80:                                         offset = data.readInt32();
  81:                                         postBuffer(offset);
  82:
  83:                                 }
  84:
  85:                             }
  86:                         }
  87:                     }
  88:
  89:                 }
  90:             }
  91:         } while (未完结);
  92:
  93:     }
  94: }

以下是媒体相关服务进程入口:

   1: int main(…)
   2: {
   3:
   4:     MediaPlayerService::instantiate()    { 见上一段代码 }
   5:     …    其他服务创建 …
   6:     ProcessState::self()->startThreadPool() { 见上一段代码 }
   7:     IPCThreadState::self()->joinThreadPool() { 见上一段代码 }
   8: }

2.9 Surface总体流程 

根据上述的Bp和Bn两侧生成过程原理分析SurfaceFlinger相关代码,可以发现: 
通过ISurfaceFlinger::createConnection,两侧生成ISurfaceFlingerClient; 
通过ISurfaceFlingerClient:: createSurface,两侧生成ISurface。 
而服务SurfaceFlinger的Bp端最初通过获取服务取得,如下:

   1: _get_surface_manager()
   2: {
   3:     if (gSurfaceManager != 0) return gSurfaceManager;
   4:  
   5:     sm = defaultServiceManager() { 详见2.8节 }
   6:  
   7:
   8:     // 获得SurfaceFlinger服务(Bp侧句柄),其原理前面章节(如2.3节)
   9:     binder = sm->getService(String16("SurfaceFlinger"));        
  10:
  11:  
  12:     // 实际产生
  13:     sp sc = interface_cast (binder)
  14:     { 详见2.4节,sc实为BpSurfaceComposer }
  15:  
  16:     if (gSurfaceManager == 0) gSurfaceManager = sc;
  17:  
  18:     return gSurfaceManager;
  19: }

加上前述Surface的分析,Surface的总体服务流程如图2所示,这些操作使得最终在客户应用中得到BpSurfaceComposer, BpSurfaceFlingerClient和BpSurface三个对象。而发起这些创建的是客户就是SurfaceFlingerClient,它在SurfaceSession(Java对象)中维护,可见SurfaceSession是创建Surface的关键对象。

clip_image002[7] 


2.10 MediaPlayerService服务总流程

   1: android_media_MediaPlayer_setDataSource(…)    /* JNI */
   2: {
   3:     sp mp = getMediaPlayer(…)
   4:     {
   5:         获得Java对象中引用的MediaPlayer对象,
   6:         它曾在android_media_MediaPlayer_native_setup中设置
   7:         即一个新建的MediaPlayer对象。
   8:         虽然它是BnMediaPlayer,但是接下来调用setDataSource将它绑定到一个远端
   9:         的MediaPlayer上
  10:     }
  11:     MediaPlayer::setDataSource(url)
  12:     {
  13:
  14:         sp &service = MediaPlayer::getMediaPlayerService()
  15:         {
  16:             sp sm = defaultServiceManager() {…}
  17:
  18:             binder = sm->getService("media.player") {…}
  19:
  20:             sMediaPlayerService = interface_cast(binder) 
  21:             { … 得到一个BpMediaPlayerService }
  22:
  23:             return sMediaPlayerService;
  24:         }
  25:
  26:             // 通过BpMediaPlayerService远程调用创建一个播放器
  27:         sp player = service->create(…) {…}
  28:         setDataSource(player)
  29:         {
  30:
  31:             mPlayer = player;    //  远端的实际功能播放器
  32:
  33:         }
  34:
  35:     }
  36: }


参考资料: 
http://hi.baidu.com/albertchen521/blog/item/30c32d3f4bee993a71cf6ca0.html 
http://www.limodev.cn/blog/archives/777

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值