Android的Binder机制浅析

Wesley13
• 阅读 532

**
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。

Android的Binder机制浅析

图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的关键对象。

[Android的Binder机制浅析  ](https://www.oschina.net/action/GoToLink?url=http%3A%2F%2Fhi.csdn.net%2Fattachment%2F201006%2F3%2F0_1275526479yjOz.gif

**
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

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Wesley13 Wesley13
2年前
Java日期时间API系列31
  时间戳是指格林威治时间1970年01月01日00时00分00秒起至现在的总毫秒数,是所有时间的基础,其他时间可以通过时间戳转换得到。Java中本来已经有相关获取时间戳的方法,Java8后增加新的类Instant等专用于处理时间戳问题。 1获取时间戳的方法和性能对比1.1获取时间戳方法Java8以前
Stella981 Stella981
2年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Wesley13 Wesley13
2年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
2年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
2个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这