Binder系列第一篇:《从getSystemService()开始,开撸Binder通讯机制》http://www.jianshu.com/p/1050ce12bc1e
Binder系列第二篇:《能用【白话文】来分析Binder通讯机制?》http://www.jianshu.com/p/fe816777f2cf
Binder系列第三篇:《Binder机制之一次响应的故事》http://www.jianshu.com/p/4fba927dce05
Binder系列第二篇已经上线!我为什么选择用【白话文】来分析Binder通讯机制?- http://www.jianshu.com/p/fe816777f2cf
始于getSystemService()
类似下面的代码,相信各位已经写了100遍了!
val accessibilityManager: AccessibilityManager = getSystemService(Context.ACCESSIBILITY_SERVICE) as AccessibilityManager
很简单,我们通过getSystemService()获取到了系统服务代理AccessibilityManager,我们通过应用内的AccessibilityManager可以系统中真正的AccessibilityManager互动。怎么做到的呢?我们慢慢来看,先从这个服务是怎么获取到的开始吧。
getSystemService()实质
我们平时调用getSystemService()实际获取到的是在SystemServiceRegistry
中注册的各种系统服务的代理,它们大多在注册的时候会通过ServiceManager.getService()
来取得和对应Service交互的IBinder对象,然后创建Service代理。
所以,ServiceManager.getService()
应该才算是真正的起点吧。这个方法CoorChice这篇文章《3分钟看懂Activity启动流程》:http://www.jianshu.com/p/9ecea420eb52 中有提到过,在那里ActivityManagerNative通过ServiceManager.getService("Activtiy")
获取到了和ActivityManager交互的IBinder对象,并使用它创建了应用程序的ActivityManagerProxy。就不多说,感兴趣的同学可以先看看那篇文章。
这是一张重要的图
还是从ServiceManager.getService()开始吧
上面这张图其实已经把整个流程描绘的很清楚了,流程不算长,接下来就根据这张图分析下。
图是从红色箭头开始看的,然后你可以跟着箭头一步一梳理这个流程,箭头上都有数字的!然后就是哪些个圈圈,相同颜色的表示同一个对象。So Sweet!
步骤1 开始创建IServiceManager
首先,既然是ServiceManager.getService()方法,那我们当然要毫不犹的直接看这个方法。
public static IBinder getService(String name) { try { // 先从缓存取 IBinder service = sCache.get(name); if (service != null) { return service; } else { // 没有就去获取 return getIServiceManager().getService(name); } } catch (RemoteException e) { Log.e(TAG, "error in getService", e); } return null; }
可以看出,ServiceManager中会缓存用过的系统服务的IBinder。只有首次使用才去获取,非常科学。需要注意的是,是通过ServiceManager中的成员IServiceManager去获取的。
接下来,我们需要看看ServiceManager的获取过程。进入getIServiceManager()方法。
private static IServiceManager getIServiceManager() { if (sServiceManager != null) { //确保sServiceManager在进程中是单例 return sServiceManager; } // 第一次会去获取sServiceManager sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject()); return sServiceManager; }
非常简单的一个方法。从中我们可以看出,IServiceManager在应用程序中是一个单例,它用于应用程序内管理Service,它实际是系统的ServiceManager的代理。
在首次调用这个方法时,自然是要创建IServiceManager。通过ServiceManagerNative.asInterface(BinderInternal.getContextObject())
这么简单的一句创建了。假象!这一句隐藏了很多玄机。我们接着探索。
步骤2 获取参数IBinder
按照代码执行顺序来,我们先看ServiceManagerNative.asInterface()
方法的参数BinderInternal.getContextObject()
干了些什么?
手动档单击进入BinderInternal.java后可以看到,这是个native方法!
public static final native IBinder getContextObject();
WTF?我好慌,而且很害怕!没JNI层源码怎么办?
《AndroidXRed》http://androidxref.com一个神奇的网站!
这个网站可以查看Android从底层到上层的所有源码,并且支持多种搜索,基本上能实现手动挡单击跳转的伪效果。非常的屌!对于CoorChice这种没什么内存,不敢编译源码的低配电脑而言,简直是福音!
现在可以看源码了,CoorChice这里选择了Lollipop - 5.0.0_r2
版本的源码。
从这里开始,你需要了解一些c/c++和JNI的知识。快复习一下吧!
步骤3 在JNI中看IBinder的获取过程
上面那个方法的JNI是在这个文件中的/frameworks/base/core/jni/android_util_Binder.cpp
。
//这些方法会通过动态注册的方式注册到BinderInternal.java中static const JNINativeMethod gBinderInternalMethods[] = { //getContextObject()就是JNI函数android_os_BinderInternal_getContextObject() { "getContextObject", "()Landroid/os/IBinder;", (void*)android_os_BinderInternal_getContextObject }, ... };
如果我们要找getContextObject()
这个名字的函数,你会发现找不见,因为这里采用了动态注册的方法来注册相关函数的。所以,我们会在上面的方法数组中发现一个字符串"getContextObject"
。嗯,就是它了。它所对应的函数是android_os_BinderInternal_getContextObject()
。
static jobject android_os_BinderInternal_getContextObject(JNIEnv* env, jobject clazz) { //通过ProcessState单例获取handle句柄为0的IBinder sp<IBinder> b = ProcessState::self()->getContextObject(NULL); return javaObjectForIBinder(env, b); }
这个函数很简单,但是暗藏玄机+1!通过ProcessState获取到了一个IBinder,并转换成Java层的IBinder返回给Java层。
接下来看看是怎么通过ProcessState获取到这个IBinder的。
步骤4 获取ProcessState的函数self()
首先,从ProcessState::self()
看来,ProcessState应该是个单例。我们到self()
里验证下。
sp<ProcessState> ProcessState::self() { Mutex::Autolock _l(gProcessMutex); if (gProcess != NULL) { // 有就直接返回 return gProcess; } //没有就创建一个ProcessState gProcess = new ProcessState; return gProcess; }
很简短的单例代码,首次调用直接new。
下面看看ProcessState对象是怎么被构造的。
步骤5 ProcessState的创建
ProcessState::ProcessState() //打开“/dev/binder”Binder驱动文件,将设备文件描述符保存在mDriverFD中 : mDriverFD(open_driver()) , mVMStart(MAP_FAILED) , mManagesContexts(false) , mBinderContextCheckFunc(NULL) , mBinderContextUserData(NULL) , mThreadPoolStarted(false) , mThreadPoolSeq(1) { ... }
主要是初始化成员变量。其中mDriverFD(open_driver())
是比较关键的一个环节,需要单独说一说。它通过调用open_driver()
函数,打开了dev/binder驱动文件,并将文件描述符赋值给mDriverFD
。那么,ProcessState作为持有Binder驱动文件描述符的对象,就拥有了和Binder驱动产生联系的资格。
下面简单看一下open_driver()
函数。
步骤6 简要分析open_driver()函数
static int open_driver(){ //打开"/dev/binder"Binder驱动文件,并获得其描述符 int fd = open("/dev/binder", O_RDWR); ... //获取Binder驱动程序的版本号 status_t result = ioctl(fd, BINDER_VERSION, &vers); ... size_t maxThreads = 15; //告知驱动程序最多可以多少条线程处理事务 result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads); ... return fd; }
这个函数主要是负责打开/dev/binder
文件,并配置一些和Binder驱动交互的参数,最后把获得的Binder驱动文件描述符fd返回。由于ProcessState在应用程序中是单例,所以保证了一个应用程序只打开一次/dev/binder
。
至于具体是怎么打开/dev/binder
文件的,后面在详细说明。这里下跳过看下一步。
步骤7 通过getContextObject()获取的IBinder是什么?
ProcessState获取到后,就要调用它的getContextObject()
函数来获取到一个IBinder对象了。
sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/) { //获取handle句柄为0的Binder return getStrongProxyForHandle(0); }
这个函数看起来是直接用来获取handle为0的IBinder的。这个为handle为0的IBinder代表着谁呢?对,你可能没猜到!它代表了系统的ServiceManager。也就是通过这个handle为0的IBinder可以和ServiceManager交互。也就是说,这个IBinder是Client用来和系统的ServiceManager交互的。这里也先不提了。
步骤8 ProcessState管理着IBinder
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle) { sp<IBinder> result; ... //尝试获取handle对应的handle_entry对象,没有的话会创建一个 handle_entry* e = lookupHandleLocked(handle); if (e != NULL) { IBinder* b = e->binder; if (b == NULL || !e->refs->attemptIncWeak(this)) { // 上面的判断确保了同一个handle不会重复创建新的BpBinder ... //创建一个BpBinder //handle为0时创建的是ServiceManager对应的BpBinder b = new BpBinder(handle); e->binder = b; if (b) e->refs = b->getWeakRefs(); result = b; //待会儿返回b } ... } return result; }
这段代码流程有点长啊,虽然CoorChice已经去掉了很大一部分了。
这里会调用lookupHandleLocked()
函数来获取一个handle_entry类型的指针。我们还是先看看这个函数吧。
ProcessState::handle_entry* ProcessState::lookupHandleLocked(int32_t handle) { //mHandleToObject是一个Vector,用于存放handle_entry结构体 //该结构体会保存handle对应的IBinder指针 const size_t N=mHandleToObject.size(); if (N <= (size_t)handle) { //没有handle对应的handle_entry就新建一个插入mHandleToObject中 //此时handle_entry还没有数据 handle_entry e; e.binder = NULL; e.refs = NULL; status_t err = mHandleToObject.insertAt(e, N, handle+1-N); if (err < NO_ERROR) return NULL; } //取出mHandleToObject中handle对应的handle_entry return &mHandleToObject.editItemAt(handle); }
很短的函数,并且注释已经足够清晰了吧?不多说了,回到getStrongProxyForHandle()
函数中。
在根据传入的handle(我们分析这个流程中handle为0)获取到对应的handle_entry后,会检查其binder成员是否存在,不存在则创建,存在直接返回。
可以看到,返回的IBinder实际是一个BpBinder类型的。这个东西也后面再说,总之它与Client发送数据到Service有关。
到此,ServiceManagerNative.asInterface()
函数就成功获取到了一个IBinder对象作为参数。下面看看它用这个参数干了啥?
步骤9、10 创建ServiceManagerProxy
拿到IBinder对象后,我们回到Java中,进入ServiceManagerNative.asInterface()
方法。你可以注意看一下上图中的红色圈,看看这个IBinder
static public IServiceManager asInterface(IBinder obj){ ... //创建一个ServiceManagerProxy return new ServiceManagerProxy(obj); }
反正最后就是使用刚刚获取到的IBinder创建了一个ServiceManagerProxy代理,用来在应用程序内代表系统的ServiceManager,并通过它和系统的ServiceManager交互。
public ServiceManagerProxy(IBinder remote) { mRemote = remote; }
可以看到,ServiceManagerProxy的构造函数十分简单。注意,ServiceManagerProxy是ServiceManagerNative的一个内部类。
实际上这个模式在CoorChice这篇文章《3分钟看懂Activity启动流程》:http://www.jianshu.com/p/9ecea420eb52中也是出现过的。
好了,既然拿到代理ServiceManagerProxy了,我们该看看getService()
方法是如何获取到相应的Service的IBinder的。
步骤11 通过IPC获取对应Service的IBinder
public IBinder getService(String name) throws RemoteException { // 准备数据包 Parcel data = Parcel.obtain(); //用于发送的数据包 Parcel reply = Parcel.obtain(); //用于响应的数据包 data.writeInterfaceToken(IServiceManager.descriptor); //将需要的Service的名字放到数据包中 data.writeString(name); //通过远程的Binder发送data到Binder驱动,并将响应保存到reply中 mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0); //从响应结果中获取可用于和Service交互的Binder IBinder binder = reply.readStrongBinder(); reply.recycle(); data.recycle(); return binder; }
在这个方法中,创建了两个Parcel数据包。data是用来发送数据的,reply是用来接收数据的。
注意mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0)
这里调用了刚刚从底层返回的IBinder对象的transact()
方法,意思是要发送数据了,并且把reply一起传过去准备接收数据。这个过程是阻塞式的。接着,当远程Service(这里指的是系统的ServiceManager)响应后,代码就可以接着走了,而这时reply中已经装了响应结果了。我们调用Parcel的readStrongBinder()
方法来取出来自Service响应的IBinder对象。然后我们拿着这个IBinder对象就可以和对应的系统Service通过IPC机制交互了。
总结
抽出空余时间写文章分享需要动力,还请各位看官动动小手点个赞,给我点鼓励
共同学习,写下你的评论
评论加载中...
作者其他优质文章