Android(安卓)binder机制(native服务篇)
** 1、前言 **
Android系统使用binder机制进行进程间通信,为了更好地封装,使用户不用关心底层细节,binder机制变得相当复杂。
binder使用c/s架构,可类比socket通信,有服务端也有客户端 ,而binder驱动就相当于网络。
Paste_Image.png本文以MediaPlayerService为例,阐述binder机制。
2、ServiceManager
ServiceManager,顾名思义,服务的管理者,所有的本地服务在启动的时候都会被保存在ServiceManager中,而用户可直接访问ServiceManager,获取所需要的服务。
ServiceManager运行在一个独立进程中,本地服务在启动时需要获取ServiceManager,将自身保存,这也是一个IPC过程。此时,ServiceManager作为服务端,而本地服务作为客户端。
以MediaPlayerService为例,查看MediaPlayerService是如何与ServiceManager通信,并将自身保存的呢?
查看MediaPlayerService.cpp的instantiate方法:
void MediaPlayerService::instantiate() {defaultServiceManager()->addService( String16("media.player"), new MediaPlayerService());}
查看defaultServiceManager源码:
sp defaultServiceManager(){if (gDefaultServiceManager != NULL) return gDefaultServiceManager;{ AutoMutex _l(gDefaultServiceManagerLock); while (gDefaultServiceManager == NULL) { gDefaultServiceManager = interface_cast( ProcessState::self()->getContextObject(NULL)); if (gDefaultServiceManager == NULL) sleep(1); }}return gDefaultServiceManager;}
现在MediaPlayerService向ServiceManager发出请求,存储服务,ServiceManager此时做为Server端,那么defaultServiceManager究竟返回的是什么对象呢?
3、痛苦的宏定义
继续查看ProcessState::self()->getContextObject(NULL)逻辑,ProcessState使用单例模式,确保一个进程中只有一个ProcessState对象。
sp ProcessState::self(){Mutex::Autolock _l(gProcessMutex);if (gProcess != NULL) { return gProcess;}gProcess = new ProcessState;return gProcess;}
ProcessState的构造方法中又做了什么呢?
ProcessState::ProcessState(): mDriverFD(open_driver()) //初始化列表模式,打开binder驱动, mVMStart(MAP_FAILED) 。。。{if (mDriverFD >= 0) { // mmap the binder, providing a chunk of virtual address space to receive transactions. mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);}
ProcessState构造方法中,打开binder驱动,整篇都在讲binder,终于提到有个类与binder驱动交互了。
继续查看getContextObject方法。
sp ProcessState::getContextObject(const sp& /*caller*/){return getStrongProxyForHandle(0);}sp ProcessState::getStrongProxyForHandle(int32_t handle){sp result;AutoMutex _l(mLock);// 根据 handle值,在Vector 中查找handle_entry* e = lookupHandleLocked(handle);if (e != NULL) { IBinder* b = e->binder; //第一次查找,显示会得到空值 if (b == NULL || !e->refs->attemptIncWeak(this)) { 。。。 // 构造一个BpBinder,最终返回它 b = new BpBinder(handle); e->binder = b; if (b) e->refs = b->getWeakRefs(); result = b; } 。。。}return result;}
回到前文的defaultServiceManager方法中,将返回值代入,得到
//注意,方法中传入的handle为0,所以BpBinder参数为0gDefaultServiceManager = interface_cast(new BpBinder(0));
interface_cast,初看以为是强制类型转换的方法,以为自己太菜,这方法怎么没见过一样,左键点击下查看方法,才发现别有洞天。
inline sp interface_cast(const sp& obj){return INTERFACE::asInterface(obj);}
原来是调用泛型类中的asInterface的方法,那么IServiceManager的asInterface的具体逻辑是什么呢?查看IServiceManager.h或者cpp文件查看,都找不到asInterface这个方法。但看到了下面一段声明:
// IServiceManager.h 中引用的DECLARE_META_INTERFACE(ServiceManager);
点击一看,这个宏定义中正好定义了asInterface 方法。
#define DECLARE_META_INTERFACE(INTERFACE) \static const android::String16 descriptor; \static android::sp asInterface( \ const android::sp& obj); \virtual const android::String16& getInterfaceDescriptor() const; \I##INTERFACE(); \virtual ~I##INTERFACE(); \
但这只是方法定义,哪里实现的呢?已经在h文件中看到宏定义了,那么cpp文件中是否会有另外一定宏定义,来实现此方法呢? 答案是肯定的,在IServiceManager.cpp中果然看到一段宏定义
IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager");
点击查看宏定义具体内容:
#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME) \const android::String16 I##INTERFACE::descriptor(NAME); \const android::String16& \ I##INTERFACE::getInterfaceDescriptor() const { \ return I##INTERFACE::descriptor; \} \android::sp I##INTERFACE::asInterface( \ const android::sp& obj) \{ \ android::sp intr; \ if (obj != NULL) { \ intr = static_cast( \ obj->queryLocalInterface( \ I##INTERFACE::descriptor).get()); \ if (intr == NULL) { \ intr = new Bp##INTERFACE(obj); \ } \ } \ return intr; \} \I##INTERFACE::I##INTERFACE() { } \I##INTERFACE::~I##INTERFACE() { } \
将模板替换,可知asInterface方法代码为:
android::sp IServiceManager::asInterface( \ const android::sp& obj) \{ \ android::sp intr; \ if (obj != NULL) { \ intr = static_cast( \ obj->queryLocalInterface( \ IServiceManager::descriptor).get()); \ if (intr == NULL) { \ intr = new BpServiceManager(obj); \ } \ } \ return intr; \}
如果有看过java中的aidl文件,会发现这段代码和aidl被编译器自动处理过后的文件非常相似,如果client端和server端不在同一进程,那么必定走的流程是返回 BpServiceManager 。
BpServiceManager 类在哪呢?它定义在IServiceManager.cpp文件中。
一般native服务的接口定义在 I××Service.h 文件中,Bp××Service一般定义在I××Service.cpp文件当中
经过一系列的折腾,终于回到MediaPlayerService.cpp的instantiate方法了,代替下就是
void MediaPlayerService::instantiate() {BpServiceManager->addService(String16("media.player"), new MediaPlayerService());}
4、和Binder驱动正式通信
查看BpServiceManager的addService方法
virtual status_t addService(const String16& name, const sp& service, bool allowIsolated){ Parcel data, reply; data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor()); data.writeString16(name); data.writeStrongBinder(service); data.writeInt32(allowIsolated ? 1 : 0); status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply); return err == NO_ERROR ? reply.readExceptionCode() : err;}
感觉这段代码非常眼熟,和java中的aidl差别不大,主要就是调用remote()->transact,和Binder驱动通信。问题来了,那remote()方法得到的是什么对象呢?
remote()方法返回的是mRemote对象,回溯上文所讲的asInterface方法,构造BpServiceManager对象,传入了一个BpBinder,查看BpServiceManager的构造函数,它最终引用父类BpRefBase的构造函数。
BpRefBase::BpRefBase(const sp& o): mRemote(o.get()), mRefs(NULL), mState(0){ 。。。。}
于是得知addService方法中,其实是调用BpBinder的transact方法。
Paste_Image.png根据在java中使用aidl的经验,调用transact方法后,最终肯定会调用到onTransact,最终调用到Server端的方法。
BpBinder的transact之后的调用流程如上,尤其关注IPCThreadState类。根据上图,IPCThreadState与Binder驱动通信,分别调用三个方法
- writeTransactionData,向Binder驱动写数据
- waitForResponse, 等待Binder驱动返回指令
- executeCommand,执行Binder驱动的指令
目前和Binder驱动相关的代码已经有两个类了,一个是ProcessState,另一个是IPCThreadState,他们的关系如何,待会再说。
已经调用了onTransact方法,按理说,应该要调用Server端的方法了,可ServiceManager的server端代码在哪里呢?
ServiceManager是一个特殊的服务,因为它是服务的管理者,它在其它服务启动之前启动,它的server端代码在Service_manager.c类中,查看它的main方法。
int main(int argc, char **argv){struct binder_state *bs;//打开Binder驱动bs = binder_open(128*1024);//将自己设定为服务的管理者,管理者对象,整个android系统只有一个if (binder_become_context_manager(bs)) { ALOGE("cannot become context manager (%s)\n", strerror(errno)); return -1;}//开启循环,从binder中读取命令,执行命令binder_loop(bs, svcmgr_handler);}
再次回到onTransact方法,现在server端代码找到了,client端调用了addService,那么server端响应了什么操作呢?
Paste_Image.png到目前为止,针对ServiceManager,从client端发起请求,到服务端响应请求的整个流程已经讲完了。
5、MediaPlayerService
根据ServiceManager的分析经验,一个本地服务至少涉及到以下几个类
- I××Service.h,定义接口,引用宏定义等,从后文可知,它还会定义BN××Service类
- I××Service.cpp,定义Bp××Service类,声明实现宏定义,从后文可知,它还会重写BN××Service类的onTransact方法
- Service_manager.c,类似的看似不相关文件,打开binder驱动,初始化,循环读取binder驱动消息等
- ××Service.cpp,I××Service.h中接口的具体实现者,ServiceManager中server端的具体逻辑实现在Service_manager.c中,但一般来说,会有这样的一个类,实现具体逻辑
MediaPlayerService服务的初始化在Main_mediaserver.cpp中,对应着ServiceManager系统的Service_manager.c,负责初始化,打开binder驱动,建议消息循环等等
int main(int argc __unused, char** argv){sp proc(ProcessState::self());sp sm = defaultServiceManager();MediaPlayerService::instantiate();ProcessState::self()->startThreadPool();IPCThreadState::self()->joinThreadPool();}
然道先前的推测不对?main方法中并没有直接打开binder,也没有建立消息循环。联想到前文中的内容,与Binder驱动打交道的主要有两个类,一是ProcessState,另一个就是IPCThreadState。
在ProcessState的构造方法中,已经打开了binder驱动。
从代码上看 ProcessState::self()->startThreadPool(),好像是启动线程。
Paste_Image.png
查看IPCThreadState的joinThreadPool方法
void IPCThreadState::joinThreadPool(bool isMain){ mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER); set_sched_policy(mMyThreadId, SP_FOREGROUND); status_t result; do { processPendingDerefs(); // 从binder驱动中取出指令并执行 result = getAndExecuteCommand(); } while (result != -ECONNREFUSED && result != -EBADF); mOut.writeInt32(BC_EXIT_LOOPER); talkWithDriver(false);}
此方法正好是建立消息死循环,与binder驱动沟通,取指令,执行指令等等。
但为什么此方法被调用两次呢?ProcessState的startThreadPool方法调用一次,而main方法最后又调用了一次,在工作线程中调用了,在主线程也调用了。是否可去掉其中之一,笔者不得而知。
IPCThreadState::self(),此方法又做了哪些工作呢?
IPCThreadState* IPCThreadState::self(){ if (gHaveTLS) {restart: const pthread_key_t k = gTLS; IPCThreadState* st = (IPCThreadState*)pthread_getspecific(k); if (st) return st; return new IPCThreadState; } pthread_mutex_lock(&gTLSMutex); if (!gHaveTLS) { int key_create_value = pthread_key_create(&gTLS, threadDestructor); if (key_create_value != 0) { pthread_mutex_unlock(&gTLSMutex); return NULL; } gHaveTLS = true; } pthread_mutex_unlock(&gTLSMutex); goto restart;}
TLS,线程局部存储,变量与线程相关,每个线程私有,不必考虑加锁问题,类似于java中的ThreadLocal类
由此可见,IPCThreadState,它是每个线程所独有的对象。
ProcessState是进程唯一的对象,这是两个非常有意思的单例。
这两个类都有与Binder驱动通信的逻辑,实质上是,IPCThreadState的构造方法中传入了ProcessState对象,IPCThreadState利用ProcessState与binder驱动通信
6、MediaPlayerService相关文件
IMediaPlayerService.h中定义了server端应该实现的接口,也定义了BnMediaPlayerService类
和前文中的IServiceManager.h一样
IMediaPlayerService.cpp中定义了BpMediaPlayerService类,也重写了BnMediaPlayerService的onTransact方法
IMediaPlayerService.h中定义的方法,在MediaPlayerService.cpp中具体实现。
7、总结
MediaPlayerService的client端与server端通信,和ServiceManager模块中类似,就不再复述。
此时再结合前言中的图片,如果每个类都做到心中有数了,那native服务的binder机制就基本了解了。
引用材料:
http://www.cnblogs.com/innost/archive/2011/01/09/1931456.html
http://blog.csdn.net/victorfreedom/article/details/43648309
http://blog.csdn.net/ykdsea/article/details/39271133
更多相关文章
- Android高德导航自定义UI
- 定义seekbar样式
- greenDAO学习分享总结
- 12.6 时间与日期
- 自定义ImageView重写onTouchEvent
- Web初试
- 安卓中找不到Theme.AppCompat.Light的解决方法
- Android(安卓)View绘制机制
- Test_TextSwitcher 使用方法