【Android源码 栏目提醒】:网学会员,鉴于大家对Android源码 十分关注,论文会员在此为大家搜集整理了“Android系统进程间通信(IPC)机制Binder中的Server启动过程源代码分析 - 电子设计”一文,供大家参考学习!
Android系统进程间通信IPC机制Binder中的Server启动过程源代码分析 在前面一篇文章
Android系统进程间通信IPC机制Binder中的Server和Client获得Service Manager接口之路中介绍了在
Android系统中Binder进程间通信机制中的Server角色是如何获得Service Manager远程接口的即defaultServiceManager函数的实现。
Server获得了Service Manager远程接口之后就要把自己的Service添加到Service Manager中去然后把自己启动起来等待Client的请求。
本文将通过分析源代码了解Server的启动过程是怎么样的。
本文通过一个具体的例子来说明Binder机制中Server的启动过程。
我们知道在
Android系统中提供了多媒体播放的功能这个功能是以服务的形式来提供的。
这里我们就通过分析MediaPlayerService的实现来了解Media Server的启动过程。
首先看一下MediaPlayerService的类图以便我们理解下面要描述的内容。
我们将要介绍的主角MediaPlayerService继承于BnMediaPlayerService类熟悉Binder机制的同学应该知道BnMediaPlayerService是一个Binder Native类用来处理Client请求的。
BnMediaPlayerService继承于BnInterfaceltIMediaPlayerServicegt类BnInterface是一个模板类它定义在frameworks/base/include/binder/IInterface.h文件中 cpp view plaincopy 1. templatelttypename INTERFACEgt 2. class BnInterface : public INTERFACE public BBinder 3. 4. public: 5. virtual spltIInterfacegt queryLocalInterfaceconst String16amp _descriptor 6. virtual const String16amp getInterfaceDescriptor const 7. 8. protected: 9. virtual IBinder onAsBinder 10. 这里可以看出BnMediaPlayerService实际是继承了IMediaPlayerService和BBinder类。
IMediaPlayerService和BBinder类又分别继承了IInterface和IBinder类IInterface和IBinder类又同时继承了RefBase类。
实际上BnMediaPlayerService并不是直接接收到Client处发送过来的请求而是使用了IPCThreadState接收Client处发送过来的请求而IPCThreadState又借助了ProcessState类来与Binder驱动程序交互。
有关IPCThreadState和ProcessState的关系可以参考上一篇文章
Android系统进程间通信IPC机制Binder中的Server和Client获得Service Manager接口之路接下来也会有相应的描述。
IPCThreadState接收到了Client处的请求后就会调用BBinder类的transact函数并传入相关参数BBinder类的transact函数最终调用BnMediaPlayerService类的onTransact函数于是就开始真正地处理Client的请求了。
了解了MediaPlayerService类结构之后就要开始进入到本文的主题了。
首先看看MediaPlayerService是如何启动的。
启动MediaPlayerService的代码位于frameworks/base/media/mediaserver/main_mediaserver.cpp文件中 cpp view plaincopy 1. int mainint argc char argv 2. 3. spltProcessStategt procProcessState::self 4. spltIServiceManagergt sm defaultServiceManager 5. LOGIquotServiceManager: pquot sm.get 6. AudioFlinger::instantiate 7. MediaPlayerService::instantiate 8. CameraService::instantiate 9. AudioPolicyService::instantiate 10. ProcessState::self-gtstartThreadPool 11. IPCThreadState::self-gtjoinThreadPool 12. 这里我们不关注AudioFlinger和CameraService相关的代码。
先看下面这句代码 cpp view plaincopy 1. spltProcessStategt procProcessState::self 这句代码的作用是通过ProcessState::self调用创建一个ProcessState实例。
ProcessState::self是ProcessState类的一个静态成员变量定义在frameworks/base/libs/binder/ProcessState.cpp文件中 cpp view plaincopy 1. spltProcessStategt ProcessState::self 2. 3. if gProcess NULL return gProcess 4. 5. AutoMutex _lgProcessMutex 6. if gProcess NULL gProcess new ProcessState 7. return gProcess 8. 这里可以看出这个函数作用是返回一个全局唯一的ProcessState实例gProcess。
全局唯一实例变量gProcess定义在frameworks/base/libs/binder/Static.cpp文件中 cpp view plaincopy 1. Mutex gProcessMutex 2. spltProcessStategt gProcess 再来看ProcessState的构造函数 cpp view plaincopy 1. ProcessState::ProcessState 2. : mDriverFDopen_driver 3. mVMStartMAP_FAILED 4. mManagesContextsfalse 5. mBinderContextCheckFuncNULL 6. mBinderContextUserDataNULL 7. mThreadPoolStartedfalse 8. mThreadPoolSeq1 9. 10. if mDriverFD gt 0 11. // XXX Ideally there should be a specific define for whether we 12. // have mmap or whether we could possibly have the kernel module 13. // availabla. 14. if definedHAVE_WIN32_IPC 15. // mmap the binder providing a chunk of virtual address space to receive transactions. 16. mVMStart mmap0 BINDER_VM_SIZE PROT_READ MAP_PRIVATE MAP_NORESERVE mDriverFD 0 17. if mVMStart MAP_FAILED 18. // sigh 19. LOGEquotUsing /dev/binder failed: unable to mmap transaction memory.nquot 20. closemDriverFD 21. mDriverFD -1 22. 23. else 24. mDriverFD -1 25. endif 26. 27. if mDriverFD lt 0 28. // Need to run without the driver starting our own thread pool. 29. 30. 这个函数有两个关键地方一是通过open_driver函数打开Binder设备文件/dev/binder并将打开设备文件描述符保存在成员变量mDriverFD中二是通过mmap来把设备文件/dev/binder映射到内存中。
先看open_driver函数的实现这个函数同样位于frameworks/base/libs/binder/ProcessState.cpp文件中 cpp view plaincopy 1. static int open_driver 2. 3. if gSingleProcess 4. return -1 5. 6. 7. int fd openquot/dev/binderquot O_RDWR 8. if fd gt 0 9. fcntlfd F_SETFD FD_CLOEXEC 10. int vers 11. if definedHAVE_
ANDROID_OS 12. status_t result ioctlfd BINDER_VERSION ampvers 13. else 14. status_t result -1 15. errno EPERM 16. endif 17. if result -1 18. LOGEquotBinder ioctl to obtain version failed: squot strerrorerrno 19. closefd 20. fd -1 21. 22. if result 0 vers BINDER_CURRENT_PROTOCOL_VERSION 23. LOGEquotBinder driver protocol does not match user space protocolquot 24. closefd 25. fd -1 26. 27. if definedHAVE_
ANDROID_OS 28. size_t maxThreads 15 29. result ioctlfd BINDER_SET_MAX_THREADS ampmaxThreads 30. if result -1 31. LOGEquotBinder ioctl to set max threads failed: squot strerrorerrno 32. 33. endif 34. 35. else 36. LOGWquotOpening /dev/binder failed: snquot strerrorerrno 37. 38. return fd 39. 这个函数的作用主要是通过open文件操作函数来打开/dev/binder设备文件然后再调用ioctl文件控制函数来分别执行BINDER_VERSION和BINDER_SET_MAX_THREADS两个命令来和Binder驱动程序进行交互前者用于获得当前Binder驱动程序的版本号后者用于通知Binder驱动程序MediaPlayerService最多可同时启动15个线程来处理Client端的请求。
open在Binder驱动程序中的具体实现请参考前面一篇文章Service Manager成为
Android进程间通信IPC机制Binder守护进程之路这里不再重复描述。
打开/dev/binder设备文件后Binder驱动程序就为MediaPlayerService进程创建了一个struct binder_proc结构体实例来维护MediaPlayerService进程上下文相关信息。
我们来看一下ioctl文件操作函数执行BINDER_VERSION命令的过程 cpp view plaincopy 1. status_t result ioctlfd BINDER_VERSION ampvers 这个函数调用最终进入到Binder驱动程序的binder_ioctl函数中我们只关注BINDER_VERSION相关的部分逻辑 cpp view plaincopy 1. static long binder_ioctlstruct file filp unsigned int cmd unsigned long arg 2. 3. int ret 4. struct binder_proc proc filp-gtprivate_data 5. struct binder_thread thread 6. unsigned int size _IOC_SIZEcmd 7. void __user ubuf void __user arg 8. 9. /printkKERN_INFO quotbinder_ioctl: d:d x lxnquot proc-gtpid current-gtpid cmd arg/ 10. 11. ret wait_event_interruptiblebinder_user_error_wait binder_stop_on_user_error lt 2 12. if ret 13. return ret 14. 15. mutex_lockampbinder_lock 16. thread binder_get_threadproc 17. if thread NULL 18. ret -ENOMEM 19. goto err 20. 21. 22. switch cmd 23. ...... 24. case BINDER_VERSION: 25. if size sizeofstruct binder_version 26. ret -EINVAL 27. goto err 28. 29. if put_userBINDER_CURRENT_PROTOCOL_VERSION ampstruct binder_version ubuf-gtprotocol_version 30. ret -EINVAL 31. goto err 32. 33. break 34. ...... 35. 36. ret 0 37. err: 38. ...... 39. return ret 40. 很简单只是将BINDER_CURRENT_PROTOCOL_VERSION写入到传入的参数arg指向的用户缓冲区中去就返回了。
BINDER_CURRENT_PROTOCOL_VERSION是一个宏定义在kernel/common/drivers/staging/
android/binder.h文件中 cpp view plaincopy 1. / This is the current protocol version. / 2. define BINDER_CURRENT_PROTOCOL_VERSION 7 这里为什么要把ubuf转换成struct binder_version之后再通过其protocol_version成员变量再来写入呢转了一圈最终内容还是写入到ubuf中。
我们看一下struct binder_version的定义就会明白同样是在kernel/common/drivers/staging/
android/binder.h文件中 cpp view plaincopy 1. / Use with BINDER_VERSION driver fills in fields. / 2. struct binder_version 3. / driver protocol version -- increment with incompatible change / 4. signed long protocol_version 5. 从注释中可以看出来这里是考虑到兼容性因为以后很有可能不是用signed long来表示版本号。
这里有一个重要的地方要注意的是由于这里是打开设备文件/dev/binder之后第一次进入到binder_ioctl函数因此这里调用binder_get_thread的时候就会为当前线程创建一个struct binder_thread结构体变量来维护线程上下文信息具体可以参考Service Manager成为
Android进程间通信IPC机制Binder守护进程之路一文。
接着我们再来看一下ioctl文件操作函数执行BINDER_SET_MAX_THREADS命令的过程 cpp view plaincopy 1. result ioctlfd BINDER_SET_MAX_THREADS ampmaxThreads 这个函数调用最终进入到Binder驱动程序的binder_ioctl函数中我们只关注BINDER_SET_MAX_THREADS相关的部分逻辑 cpp view plaincopy 1. static long binder_ioctlstruct file filp unsigned int cmd unsigned long arg 2. 3. int ret 4. struct binder_proc proc filp-gtprivate_data 5. struct binder_thread thread 6. unsigned int size _IOC_SIZEcmd 7. void __user ubuf void __user arg 8. 9. /printkKERN_INFO quotbinder_ioctl: d:d x lxnquot proc-gtpid current-gtpid cmd arg/ 10. 11. ret wait_event_interruptiblebinder_user_error_wait binder_stop_on_user_error lt 2 12. if ret 13. return ret 14. 15. mutex_lockampbinder_lock 16. thread binder_get_threadproc 17. if thread NULL 18. ret -ENOMEM 19. goto err 20. 21. 22. switch cmd 23. ...... 24. case BINDER_SET_MAX_THREADS: 25. if copy_from_userampproc-gtmax_threads ubuf sizeofproc-gtmax_threads 26. ret -EINVAL 27. goto err 28. 29. break 30. ...... 31. 32. ret 0 33. err: 34. ...... 35. return ret 36. 这里实现也是非常简单只是简单地把用户传进来的参数保存在proc-gtmax_threads中就完毕了。
注意这里再调用binder_get_thread函数的时候就可以在proc-gtthreads中找到当前线程对应的struct binder_thread结构了因为前面已经创建好并保存在proc-gtthreads红黑树中。
回到ProcessState的构造函数中这里还通过mmap函数来把设备文件/dev/binder映射到内存中这个函数在Service Manager成为
Android进程间通信IPC机制Binder守护进程之路一文也已经有详细介绍这里不再重复描述。
宏BINDER_VM_SIZE就定义在ProcessState.cpp文件中 cpp view plaincopy 1. define BINDER_VM_SIZE 110241024 - 4096 2 mmap函数调用完成之后Binder驱动程序就为当前进程预留了BINDER_VM_SIZE大小的内存空间了。
这样ProcessState全局唯一变量gProcess就创建完毕了回到frameworks/base/media/mediaserver/main_mediaserver.cpp文件中的main函数下一步是调用defaultServiceManager函数来获得Service Manager的远程接口这个已经在上一篇文章
Android系统进程间通信IPC机制Binder中的Server和Client获得Service Manager接口之路有详细描述读者可以回过头去参考一下。
再接下来就进入到MediaPlayerService::instantiate函数把MediaPlayerService添加到Service Manger中去了。
这个函数定义在frameworks/base/media/libmediaplayerservice/MediaPlayerService.cpp文件中 cpp view plaincopy 1. void MediaPlayerService::instantiate 2. defaultServiceManager-gtaddService 3. String16quotmedia.playerquot new MediaPlayerService 4. 我们重点看一下IServiceManger::addService的过程这有助于我们加深对Binder机制的理解。
在上一篇文章
Android系统进程间通信IPC机制Binder中的Server和Client获得Service Manager接口之路中说到defaultServiceManager返回的实际是一个BpServiceManger类实例因此我们看一下BpServiceManger::addService的实现这个函数实现在frameworks/base/libs/binder/IServiceManager.cpp文件中 cpp view plaincopy 1. class BpServiceManager : public BpInterfaceltIServiceManagergt 2. 3. public: 4. BpServiceManagerconst spltIBindergtamp impl 5. : BpInterfaceltIServiceManagergtimpl 6. 7. 8. 9. ...... 10. 11. virtual status_t addServiceconst String16amp name const spltIBindergtamp service 12. 13. Parcel data reply 14. data.writeInterfaceTokenIServiceManager::getInterfaceDescriptor 15. data.writeString16name 16. data.writeStrongBinderservice 17. status_t err remote-gttransactADD_SERVICE_TRANSACTION data ampreply 18. return err NO_ERROR reply.readExceptionCode 19. 20. 21. ...... 22. 23. 这里的Parcel类是用来于序列化进程间通信数据用的。
先来看这一句的调用 cpp view plaincopy 1. data.writeInterfaceTokenIServiceManager::getInterfaceDescriptor IServiceManager::getInterfaceDescriptor返回来的是一个字符串即quotandroid.os.IServiceManagerquot具体可以参考IServiceManger的实现。
我们看一下Parcel::writeInterfaceToken的实现位于frameworks/base/libs/binder/Parcel.cpp文件中 cpp view plaincopy 1. // Write RPC headers. previously just the interface token 2. status_t Parcel::writeInterfaceTokenconst String16amp interface 3. 4. writeInt32IPCThreadState::self-gtgetStrictModePolicy 5. STRICT_MODE_PENALTY_GATHER 6. // currently the interface identification token is just its name as a string 7. return writeString16interface 8. 它的作用是写入一个整数和一个字符串到Parcel中去。
再来看下面的调用 cpp view plaincopy 1. data.writeString16name 这里又是写入一个字符串到Parcel中去这里的name即是上面传进来的“media.player”字符串。
往下看 cpp view plaincopy 1. data.writeStrongBinderservice 这里定入一个Binder对象到Parcel去。
我们重点看一下这个函数的实现因为它涉及到进程间传输Binder实体的问题比较复杂需要重点关注同时也是理解Binder机制的一个重点所在。
注意这里的service参数是一个MediaPlayerService对象。
cpp view plaincopy 1. status_t Parcel::writeStrongBinderconst spltIBindergtamp val 2. 3. return flatten_binderProcessState::self val this 4. 看到flatten_binder函数是不是似曾相识的感觉我们在前面一篇文章Service Manager成为
Android进程间通信IPC机制Binder守护进程之路中曾经提到在Binder驱动程序中使用struct flat_binder_object来表示传输中的一个binder对象它的定义如下所示 cpp view plaincopy 1. / 2. This is the flattened representation of a Binder object for transfer 3. between processes. The offsets supplied as part of a binder transaction 4. contains offsets into the data where these structures occur. The Binder 5. driver takes care of re-writing the structure type and data as it moves 6. between processes. 7. / 8. struct flat_binder_object 9. / 8 bytes for large_flat_header. / 10. unsigned long type 11. unsigned long flags 12. 13. / 8 .