(本文适合对Binder框架具有基本了解,但缺乏感性认识的读者。为流畅阅读本文,读者还需要对Android Framework、Linux Kernel有一定的理解,并且手上最好有整套可编译的安卓6.0源代码,以便复现分析步骤。如有转载,请注明出自本博客。)
正文开始
下图是一张常见的Binder通信机制流程图:
现在我们从细节入手,以PowerManager内部类WakeLock提供的获取亮屏锁函数acquire()为例,分析客户端的上层Binder请求是如何一层一层地向下传递到驱动端。为便于跟踪,需要创建一个demo程序,在demo程序中添加一个按钮,在按钮的onClick()函数中添加以下代码:
String TAG = "BinderDemo";
PowerManager.WakeLock wakeLock;
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
wakeLock = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "hello binder");
if (null != wakeLock) {
Log.d(TAG, "before calling wakeLock.acquire()");
wakeLock.acquire(); // 关键代码
Log.d(TAG, "after calling wakeLock.acquire()");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
wakeLock.release();
}
然后,编译demo程序并安装到手机中。
在上述代码中,首先获取电源管理PowerManager的一个WakeLock实例,然后通过该实例调用WakeLock类的acquire()函数。acquire()函数实际上会构造一个Binder请求,向下传递给Binder驱动设备,Binder驱动设备收到这个请求后,会根据这个请求所附带的Binder引用信息,找到对应的Binder服务端,将这个请求添加到Binder服务端的工作任务列表,此时客户端线程进入等待状态。在本例中,这个服务端就是PowerManagerService。当服务端完成这个请求后,会把结果传回Binder驱动,此时客户端线程收到返回数据,结束等待,一层一层地向上返回,直到退出acquire()函数。
上述过程涉及的代码很长很复杂,跨越了不同的进程,从app上层深入到底层kernel,又从底层kernel传递信号到服务端上层java代码,服务端上层代码处理完成后,返回给kernel层,然后又从kernel层返回到客户端app的上层,这一路峰回路转,机关暗藏,但呈现给开发人员的只有短短一句wakeLock.acquire(),这充分体现了Binder机制的巧妙设计。
接下来我们跟踪acquire()函数,看看