Native层流程大纲
介绍完Binder驱动的构架后,下面我们进入到Binder Native层的流程分析。Binder的整体流程可分为如下几个步骤:
- Service Manager成为守护进程--- Service Manager告知Binder驱动程序它是Binder机制的上下文管理者。
- Server和Client获得Service Manager的远程接口--- defaultServiceManager接口是如何实现的。
- Server向SM注册服务---- IServiceManager::addService接口是如何实现的
- Client从SM获得服务----IServiceManager::getService接口是如何实现的
其中,第2步是3和4的基础。上面4个步骤,是系统中Binder驱动和Native层的主要工作,而Binder Java层的每次调用底层函数都离不开这4步的操作。这里介绍Native层,Java层将在下章节介绍。
4.1 SM成为守护进程
SM成为守护进程的过程中,与驱动交互频繁,下面会结合之前的驱动框架来分析:
- Service Manager在用户空间的源代码位于frameworks/base/cmds/servicemanager 目录下,主要是由binder.h、binder.c和service_manager.c三个文件组成。
- Service Manager的入口位于service_manager.c文件中的main函数。Main函数主要有三个功能:
- 打开Binder设备文件;
- 调用mmap
- 告诉Binder驱动程序自己是Binder上下文管理者,即我们前面所说的守护进程;
- 进入一个无穷循环,充当Server的角色,等待Client的请求
4.1.1打开Binder设备文件
在service_manager.c打开Binder设备文件的核心代码见下图:
函数首先是执行打开Binder设备文件的操作binder_open,这个函数位于frameworks/base/cmds/servicemanager/binder.c文件中, 代码如下:
主要做了2件主要的事情:
- 打开驱动创建的/dev/binder文件结点,创建binder_proc结构体,保存/dev/binder上下文信息
- 调用驱动的mmap分配空间
4.1.2 打开设备详细分析
- 通过文件操作函数open打开/dev/binder设备文件,(/dev/binder是在Binder驱动模块初始化时创建的,创建入口在binder_init());此处调用驱动函数binder_open(),功能如下:
- 创建struct binder_proc,保存打开设备文件的进程上下文信息到struct file的私有变量private_data中
- binder_proc下,会挂4棵红黑树的节点:
- threads树:用来保存binder_proc进程内用于处理用户请求的线程
- node树:保存binder_proc进程内的binder实体
- refs_by_desc和refs_by_node:保存binder_proc进程内的Binder引用(前者以句柄,后者以节点地址的key来组织)
- 调用驱动的binder_mmap(),对打开的设备文件进行内存映射mmap:
- 通过filp->private_data得到打开/dev/binder时创建的binder_proc结构。
- 同一块地址,会通过struct vm_area_struct 映射用户空间server进程的使用信息;通过struct vm_struct 同时映射给内核;
- 好处:这样,同一块物理地址分别映射给了内核和server进程,就减少了数据从内核到server的拷贝了。 (一般是:client到内核、内核到server)
- 检查:映射内存大小不能超过4M(此处是128*1024为128K)
- 调用get_vm_area()获得空间的vm_struct 空间,初始化binder_proc结构体
- 调用binder_update_pange_range()为虚拟地址空间分配空闲的物理页面
4.1.3 成为守护进程
回到frameworks/base/cmds/servicemanager/service_manager.c文件中的main函数,下一步就是调用binder_become_context_manager来通知Binder驱动程序自己是Binder机制的上下文管理者,即守护进程。
binder_become_context_manager函数位于frameworks/base/cmds/servicemanager/binder.c文件中,
这里通过调用ioctl文件操作函数来通知Binder驱动程序自己是守护进程,命令号是BINDER_SET_CONTEXT_MGR,流程如下:
- 通过filp->private_data获得proc变量
- 通过binder_get_thread()获得线程信息,其流程如下:
- 把当前线程pid作为键值,在进程proc->thread表示的红黑树中进行查找,看是否创建了binder_thread信息;如果没有创 建,创建完后会插入到proc->threads红黑树中,下次就可从proc中找到
- 碰到binder_context_mgr_node和binder_context_mgr_uid。由于第一次用到,binder_context_mgr_node表示SM的实体,此时为null; binder_context_mgr_uid表示SM守护进程的id,此时为-1;于是会初始化binder_context_mgr_uid为current->cred->euid,这样当前线程就成为Binder机制的守护进程了,并且通过binder_new_node为Service Manager创建Binder实体。
- 如果第3步创建了新的binder_node,就会把新建的binder_node指针保存在binder_context_mgr_node中
4.1.4进入loop循环
回到frameworks/base/cmds/servicemanager/service_manager.c文件中的main函数中,继续往下看,会看到调用了binder_loop()函数进入循环,等待Client来请求。
binder_loop函数定义在frameworks/base/cmds/servicemanager/binder.c文件中,流程如下:
- 首先是通过binder_write()执行BC_ENTER_LOOPER命令告诉Binder驱动程序,Service Manager要进入循环了,调用驱动 ioctl():
- 调用binder_get_thread函数获取binder_thread,就能从proc中直接找到了,不需要创建一个新的。这里进入case BINDER_WRITE_READ:
- 首先是通过copy_from_user(&bwr, ubuf, sizeof(bwr))语句把用户传递进来的参数转换成struct binder_write_read 结构,并保存在本地变量bwr中,这里可以看出bwr.write_size等于4,
- 于是进入binder_thread_write函数,这里我们只关注BC_ENTER_LOOPER相关的代码
- 在执行完BC_ENTER_LOOPER时,thread->looper值就变为BINDER_LOOPER_STATE_ENTERED了,表明当前线程进入循环状态了
- 回到binder_ioctl函数,由于bwr.read_size == 0,binder_thread_read函数就不会被执行了,这样,binder_ioctl的任务就完成了
- 回到binder_loop函数,进入for循环,又会执行一个ioctl(bs->fd, BINDER_WRITE_READ, &bwr); 由于bwr.write_size等于0,会执行binder_thread_write函数,bwr.read_size等于32,于是进入到binder_thread_read()。
4.1.5 SM成为守护进程-总结
至此,我们就从源代码一步一步地分析完Service Manager是如何成为Android进程间通信(IPC)机制Binder守护进程的了。总结一下,Service Manager是成为Android进程间通信(IPC)机制Binder守护进程的过程是这样的:
1. 打开/dev/binder文件:open("/dev/binder", O_RDWR);
2. 建立128K内存映射:mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
3. 通知Binder驱动程序它是守护进程:binder_become_context_manager(bs);
4. 进入循环等待请求的到来:binder_loop(bs, svcmgr_handler);
在这个过程中,在Binder驱动程序中建立了一个struct binder_proc结构、一个struct binder_thread结构和一个struct binder_node结构,这样,Service Manager就在Android系统的进程间通信机制Binder担负起守护进程的职责了。
4.2 Server和Client获得Service Manager远程接口
我们知道,Service Manager在Binder机制中既充当守护进程的角色,同时它也充当着Server角色,然而它又与一般的Server不一样。对于普通的Server来说,Client如果想要获得Server的远程接口,那么必须通过Service Manager远程接口提供的getService接口来获得,这本身就是一个使用Binder机制来进行进程间通信的过程。而对于Service Manager这个Server来说,Client如果想要获得Service Manager远程接口,却不必通过进程间通信机制来获得,因为Service Manager远程接口是一个特殊的Binder引用,它的引用句柄一定是0。
获取Service Manager远程接口的函数是defaultServiceManager,这个函数声明在frameworks/base/include/binder/IServiceManager.h文件中:
4.2.1 Service Manager继承关系
那么为什么要获取远程端口呢?!是因为要实现业务以及完成通信。先来看看网上的一个关于继承关系的图示:
IServiceManager类提供的业务函数:getService(), checkService(), addService();
BpServiceManager类继承了BpInterface类,而BpInterface类继承了BpRefBase类。
在BpRefBase类中,有一个成员变量mRemote,它的类型是IBinder*,实现类为BpBinder,它表示一个Binder引用,引用句柄值保存在BpBinder类的mHandle成员变量中。
BpBinder类通过IPCThreadState类来和Binder驱动程序并互,而IPCThreadState又通过它的成员变量mProcess来打开/dev/binder设备文件,mProcess成员变量的类型为ProcessState。
ProcessState类打开设备/dev/binder之后,将打开文件描述符保存在mDriverFD成员变量中,以供后续使用。
4.2.2 defaultServiceManager
理清了上述的继承关系后,我们再来看看defaultServicemanager这个函数。
从这个函数可以看出:gDefaultServiceManager是单例模式,调用defaultServiceManager函数时,如果gDefaultServiceManager已经创建,则直接返回,否则通过interface_cast<IServiceManager>(ProcessState::self()->getContextObject(NULL))来创建一个,并保存在gDefaultServiceManager全局变量中。
在这个过程中,有4个关键步骤:
- 调用ProcessStaate::self()
- 调用getContextObject(NULL)
- 使用interface_cast
- 使用 <IserviceManager>
下面来分析这4个步骤
4.2.2.1 ProcessState::self()
ProcessState::self()是ProcessState的静态成员函数,它的作用是返回一个全局唯一的ProcessState实例变量,就是单例模式了,这个变量名为gProcess。如果gProcess尚未创建,就会执行创建操作,在ProcessState的构造函数中,会通过open文件操作函数打开设备文件/dev/binder,并且返回来的设备文件描述符保存在成员变量mDriverFD中。也就是得到了一个可以和底层打交道的ProcessState类型的gProcess对象。在addervice()的流程里,会深入分析。
4.2.2.2 getContextObject()
gProcess->getContextObject(NULL),传递的值为NULL即0,返回的值为sp<IBinder>类型的getStrongProxyForHandle(0)。getStrongProxyForHanlde(int32_t handle)中,handle的值是一个资源项数组中的索引值。
- 作用:根据索引查找对应的资源,如果lookupHandleLocked发现没有对应资源项,则创建一个新的BpBinder项,填充BpBinder,并返回(handle值为0)
结果为:返回一个handle为0的Binder引用,即BpBinder;于是创建Service Manager远程接口的语句可以简化为:gDefaultServiceManager = interface_cast<IServiceManager>(new BpBinder(0));
4.2.2.3 interface_cast
再来看函数interface_cast<IServiceManager>的实现,它是一个模板函数,定义在framework/base/include/binder/IInterface.h文件中:
这里的《INTERFACE>是IServiceManager,于是调用了IServiceManager::asInterface函数,那么 gDefaultServiceManager = interface_cast<IServiceManager>(new BpBinder(0)); 可以变成:gDefaultServiceManager = IServiceManager::asInterface(new BpBinder(0));
IserviceManager::asInterface是通过DECLARE_META_INTERFACE(ServiceManager)宏在IServiceManager类中声明的,它位于framework/base/include/binder/IServiceManger.h文件中。IServiceManager::asInterface的实现是通过IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager")宏定义的,它位于framework/base/libs/binder/IServiceManager.cpp文件中。
4.2.2.4 IServiceManager::asInterface
最终,在IServiceManager::asInterface函数中会调用:Return intr = new BpServiceManager(obj); 这里的obj就则刚才创建的new BpBinder(0),上面的代码为:
- intr = new BpServiceManager(new BpBinder(0));
回到defaultServiceManager函数中,最终结果为:gDefaultServiceManager = new BpServiceManager(new BpBinder(0));
这样,Service Manager远程接口就创建完成了,它本质上是一个BpServiceManager,包含了一个句柄值为0的Binder引用。这里,实现asInterface函数,是利用BpBinder对象新建了一个BpServiceManager对象
4.3 Server向SM注册服务
实际上,BnMediaPlayerService并不是直接接收到Client处发送过来的请求,而是使用了IPCThreadState接收Client处发送过来的请求,而IPCThreadState又借助了ProcessState类来与Binder驱动程序交互。
IPCThreadState接收到了Client处的请求后,就会调用BBinder类的transact函数,并传入相关参数,BBinder类的transact函数最终调用BnMediaPlayerService类的onTransact函数,于是,就开始真正地处理Client的请求了。
以MediaServer作为Server的例子,这里我们只看MediaPlayerService:多媒体系统的重要服务。MS的入口函数在 \frameworks\av\media\mediaserver\ main_mediaserver.cpp 如下图,
可分为5步:
- 创建ProcessState
- 创建IServiceManager对象
- 初始化MediaPlayerService服务对象
- 创建进程的线程池
- 把自己加入线程池
下面来分别分析。
4.3.1 ProcessState
之前分析过,这里详细介绍下参数传递的流程。ProcessState::self()调用创建一个ProcessState实例。ProcessState::self()是ProcessState类的一个静态成员变量,定义在frameworks/base/libs/binder/ProcessState.cpp文件中:
这里可以看出,这个函数作用是返回一个全局唯一的ProcessState实例gProcess。全局唯一实例变量gProcess定义在frameworks/base/libs/binder/Static.cpp文件中
再来看ProcessState的构造函数:ProcessState::ProcessState()的流程:
- 通过open_driver()打开binder设备 /dev/binder,并将打开设备文件描述符保存在成员变量mDriverFD中,这样,与Binder驱动有了交互的通道。open_driver这个函数同样位于frameworks/base/libs/binder/ProcessState.cpp文件中,流程如下:
- 通过调用驱动open()打开/dev/binder,在打开/dev/binder设备文件后,Binder驱动程序就为MediaPlayerService进程创建了一个struct binder_proc结构体实例来维护MediaPlayerService进程上下文相关信息。
- 调用ioctl()执行BINDER_VERSION获得当前Binder驱动程序的版本号。将BINDER_CURRENT_PROTOCOL_VERSION写入到传入的参数arg指向的用户缓冲区中。
- 调用ioctl()执行BINDER_SET_MAX_THREADS,通知Binder驱动程序最多能设置多少个线程,MediaPlayerService最多可同时启动15个线程来处理Client端的请求。把用户传进来的参数保存在proc->max_threads中就完毕了。(注意,这里再调用binder_get_thread函数的时候,就可以在proc->threads中找到当前线程对应的struct binder_thread结构了,因为前面已经创建好并保存在proc->threads红黑树中)
- 对返回的fd使用mmap,把设备文件/dev/binder映射到内存中(流程见“成为守护进程mmap"部分)
这样,ProcessState全局唯一变量gProcess就创建完毕了,回到了frameworks/base/media/mediaserver/main_mediaserver.cpp文件中的main函数
4.3.2 创建IServiceManager对象
DefaultServiceManager函数的实现在之前分析过,则:sp<IServiceManager> sm = defaultServiceManager(); 为:sp<IServiceManager> sm = new BpServiceManager(new BpBinder(0));
4.3.3 注册MediaPlayerService
MediaPlayerService::instantiate()调用:defaultServiceManager()->addService()。这个函数最终会通过IPCthreadState->transact()和Binder驱动打交道,把数据传送到SM中,完成MediaPlayerService的注册。defaultServiceManager()返回的对象是BpServiceManager,而BpServiceManager是IServiceManager的后代。IServiceManager是一个抽象类,里面有我们操作业务层的各种函数。
4.3.3.1 MediaPlayerService::instantiate()
MediaPlayerService::instantiate();的实现如下:
这里,实际上是调用的BpServiceManger::addService()这个函数实现在frameworks/base/libs/binder/IServiceManager.cpp文件中的addService()。addService是一个业务层的函数,调用remote()->transact();remote()返回的是mRemote,也就是BpBinder对象。在addService函数中,把请求数据打包成data后,传递给了BpBinder的transact函数,把通信任务交给了BpBinder;即交给了通信层去处理。
4.3.3.2 transact()通信层的工作
BpBinder::transact()调用了:status_t status = IPCThreadState::self()->transact(mHandle, code, data, reply, flags);
这里的mHandle为0,code为ADD_SERVICE_TRANSACTION。ADD_SERVICE_TRANSACTION是上面以参数形式传进来的,这里表示的是Service Manager远程接口,mHandle的句柄值一定是0。即,把transact工作交给了IPCThreadState。IPCThreadState::self()中,TLS: Thread Local Storage,每个线程都有,且不共享。通过pthread_getspecific/pthread_setspecific函数可以获得/设置这些空间中的内容。
流程如下:
- pthread_getspecific()从线程本地存储空间中获得保存在其中的IPCThreadState对象
- new一个IPCThreadState对象,调用构造函数,构造函数中会调用pthread_setspecific函数。则上面的调用变为: new IPCThreadState()->transact(mHandle, code, data, reply, flags);
- 构造函数 IPCThreadState()的流程:
- pthread_setspecific() 把自己设置到线程本地存储中
- 设置mIn和mOut搜法命令的缓冲区
- IPCThreadState::transact()调用:
- err = writeTransactionData(BC_TRANSACTION,...); 函数里会创建一个binder_transaction_data tr,这个就是等下要传给Binder驱动的。发送的消息码为:BC_XX
- 该函数原型为:IPCTheadState::writeTransactionData(int32_t cmd, uint32_t binderFlags, int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer)
- 其中函数中定义的binder_transaction_data是和binder设备通信的数据结构 binder_transaction_data tr;
- handle的值传递给了target用来标识目的端,其中0为SM的标志。tr.target.handle = handle;
- cmd:发送的命令消息码 BC_XXX,此处为BC_TRANSACTION
- code: 用来switch/case的消息码
- 把命令写到mOut中,并不直接发出去。mOut.writeInt32(cmd); mOut.write(&tr, sizeof(tr));
- 这时,已经把addService的请求信息”tr”写到mOut中了,写入的内容为:
- 该函数原型为:IPCTheadState::writeTransactionData(int32_t cmd, uint32_t binderFlags, int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer)
- err = waitForResponse(reply); binder设备向应用程序回复消息,BR_XX为回复的消息码
- 接收回复的数据waitForResponse(Rarcel *reply, status_t *acquireResult)。在无限循环中(数据读完或异常,则退出)做了如下事情:
- 调用talkWithDriver();
- 其中定义了binder_write_read bwr; 一个与binder设备交换数据的结构;这里调用了驱动的ioctl()与驱动交互:
- 写流程:
- 请求命令填充
- 调用ioctl,由binder驱动实现具体操作
- 读流程:
- 接收数据缓冲区信息的填充,如果以后收到数据,就填到mIn中
- 调用ioctl,由binder驱动实现具体操作
- 写流程:
- 其中定义了binder_write_read bwr; 一个与binder设备交换数据的结构;这里调用了驱动的ioctl()与驱动交互:
- 把数据读到mIn中
- 把命令(BR_XXX)读出并switch/case
- executeCommand(cmd)执行命令
- executeCommand(int32_t cmd)收到cmd后,switch(cmd):
- case BR_ERROR:
- case BR_TRANSACTION:
- sp<BBinder>b((BBinder*)tr.cookie); 设置BnServiceXXX的对象b,BnServiceXXX是从BBinder派生
- b->transact(); 调用transact函数,发送binder_transaction_data和Parcel类型的数据
- case BR_DEAD_BINDER:
- 收到Binder驱动发来的service死掉的消息,只有Bp端能收到
- case BR_SPAWN_LOOPER:
- 收到来自驱动的指示以创建一个新线程,用于和Binder通信
- 收到来自驱动的指示以创建一个新线程,用于和Binder通信
- 调用talkWithDriver();
- 接收回复的数据waitForResponse(Rarcel *reply, status_t *acquireResult)。在无限循环中(数据读完或异常,则退出)做了如下事情:
- err = writeTransactionData(BC_TRANSACTION,...); 函数里会创建一个binder_transaction_data tr,这个就是等下要传给Binder驱动的。发送的消息码为:BC_XX
- 构造函数 IPCThreadState()的流程:
4.3.4 StartThreadPool()
StartThreadPool()调用spawnPooledThread()函数:sp<Thread> t = new PoolThread(isMain); isMain参数是true; PoolThread是在IPCThreadState中定义了一个Thread子类。PoolThread类中,调用threadLoop()。threadLoop()中,在这个线程中又创建了一个IPCThreadState: IPCThreadState::self()->joinThreadPool(mIsMain)。
joinThreadPool()流程:
- mOut.writeInt32(isMain?BC_ENTER_LOOPER: BC_REGISTER_LOOPER); 如果isMain为true,则需要循环处理。把请求写到mOut中,过会一起发出
- 处理已经死亡的BBinder对象
- 发送命令,读取请求:调用talkWithDriver();
4.3.5 MS中的joinThreadPool()
MediaServer进程一共注册了4个服务。MS中目前有两个线程在talkWithDriver():
- 一个是StartThreadPool启动新线程通过joinThreadPool,调用talkWithDriver(),读取binder设备;
- 另一个是MS主线程调用joinThreadPool,调用talkWithDriver(),读取binder设备
BnService和BpService负责业务的交互;BBinder和BpBinder负责通信的交互
4.3.6 MediaServer注册服务到SM流程图
4.4 Client从SM获得服务
client从SM获得服务,也就是从SM获得 BpMediaPlayerService。BpMediaPlayerService的构造函数有一个参数impl,它的类型为const sp<IBinder>&,从上面的描述中,这个实际上就是一个BpBinder对象。这样,要创建一个BpMediaPlayerService对象,首先就要有一个BpBinder对象。再来看BpBinder类的构造函数,它有一个参数handle,类型为int32_t,这个参数的意义就是请求MediaPlayerService这个远程接口的进程对MediaPlayerService这个Binder实体的引用了。因此,获取MediaPlayerService这个远程接口的本质问题就变为从Service Manager中获得MediaPlayerService的一个句柄了。
4.4.1 详细分析:
这里我们以MediaServer中的MediaPlayService与Client交互为例,来了解请求数据是如何从通信层传递到业务层并进行处理的:
client想要获得某个Service的信息,就得先和SM交互,通过调用getService()来获得对应的Service信息,这里用到的是IMediaDeathNotifier::getMeidaPlayerService()
- 通过defaultServiceManager()获得SM的远程接口BpServiceManager的IServiceManager接口
- 用while循环通过binder= sm->getService()不断尝试获得名字为”media.player”的service;向SM查询对应服务的信息,返回一个与MediaPlayerService通信的BpBinder;如果SM上还没有注册对应的服务,则睡0.5秒再尝试,直到对应服务注册到SM上才中止
- 通过interface_cast,将这个binder转换成一个BpMediaPlayerService
有了BpMediaPlayerService,client就能够使用任何IMediaPlayerService提供的业务逻辑函数了,e.g: createMediaRecorder和createMetadataRetriever等。调用这些函数都将把请求数据打包发给Binder驱动,并由BpBinder中handle知道对应端的处理者来处理,包括
- 通信层接收到请求
- 递交给业务层处理
BpServiceManager::getService通过BpServiceManager::checkService执行操作。
在BpServiceManager::checkService中:
- 首先是通过Parcel::writeInterfaceToken往data写入一个RPC头;就是写往data里面写入了一个整数和一个字符串“android.os.IServiceManager”, Service Manager来处理CHECK_SERVICE_TRANSACTION请求之前,会先验证一下这个RPC头,看看是否正确。接着再往data写入一个字符串name,这里就是“media.player”了
- 调用remote()返回的是一个BpBinder,于是,就进行到BpBinder::transact函数了。这里的mHandle = 0,code = CHECK_SERVICE_TRANSACTION,flags = 0。进入到IPCThread::transact函数中:
- 首先是调用函数writeTransactionData写入将要传输的数据到IPCThreadState的成员变量mOut中去
- 调用waitForResponse(reply),这个函数通过IPCThreadState::talkWithDriver与驱动程序进行交互,这里的needRead为true,因此,bwr.read_size大于0;outAvail也大于0,因此,bwr.write_size也大于0;
- 最后ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr)
- 通信层
- 首先server和client都调用了ProcessState的构造函数从而都向驱动申请了一块物理内存用于通信数据的存放
- server调用SM的addService函数传递一个字符串和实际Binder对象在自己虚拟地址空间的地址到Binder驱动,Binder驱动记录下该地址值,在SM申请的物理内存中分配一个虚拟地址并连同字符串一起传递给SM,而且Binder驱动会记录下两个地址之间的对应关系.
- client调用SM的getService函数传递一个字符串给SM,SM将相对应的虚拟地址值传递给Binder驱动,Binder驱动查询出实际对象的地址,在client申请的物理内存中分配一个虚拟地址并传递给client,而且Binder驱动会记录下这个地址和实际Binder对象地址之间的对应关系,client这里得到的就是实际Binder的引用了。到了这一步,真正的Binder对象就拥有两个引用,一个在SM,一个client.
- client通过得到的Binder引用调用server中的函数,驱动会根据传递过来引用值找到应该处理该请求的进程,并唤醒其中的Binder线程,调用BBinder对象的onTransaction函数,最终调用到实际的函数
- 从通信层到业务层
- 从bpxxxService的构造函数可以看出,在Client进程,每一个BpxxxService对象都封装了一个BpBinder对象,因此,确切来说,Client进程缓存的是BpBinder对象,每一个BpBinder对象都与一个Binder句柄值对应。每当Client进程需要创建一个BpxxxService对象时,就会检查本地缓存中是否已经存在对应的BpBinder对象。如果存在的话,就可以直接使用它来创建一个BpxxxService对象,否则的话,就要通过Binder驱动程序来获得一个Binder句柄值,再以这个句柄值来创建一个BpBinder对象,最后再根据这个BpBinder对象来创建一个BpxxxService对象。
- 从bpxxxService的构造函数可以看出,在Client进程,每一个BpxxxService对象都封装了一个BpBinder对象,因此,确切来说,Client进程缓存的是BpBinder对象,每一个BpBinder对象都与一个Binder句柄值对应。每当Client进程需要创建一个BpxxxService对象时,就会检查本地缓存中是否已经存在对应的BpBinder对象。如果存在的话,就可以直接使用它来创建一个BpxxxService对象,否则的话,就要通过Binder驱动程序来获得一个Binder句柄值,再以这个句柄值来创建一个BpBinder对象,最后再根据这个BpBinder对象来创建一个BpxxxService对象。
- 业务层
- 由于BpMediaPlayerService继承了IMediaPlayerService,IXXService有比如createMediaRecord(), CreateMetaDataRetrive()等业务层方法,则可以完成相应业务需要 http://www.jsqj.cc 军事新闻