By 高焕堂 2011/09/09
[ IT史上最完整、最经典的软件框架开发技术宝典 (上百篇经典文章&eBooks) ]
[Go Back]
HAL(Hardware Abstraction Layer)技术观点(7):
如何包装IBinder接口呢?
1. 从模块角度,转换成接口(Interface)角度
许多人对于模块(或称模块)比较关心,而对该其接口(Interface)反而比较不关心。相对上,模块是比较实的,而接口是比较虚的,所以大家容易忽略之。笔者在2011年撰写的新书,就特别强调接口是Android相关厂商赢家密码所在。例如,就ServiceManager而言,我们通常关心的是:它是一个Native Service,在系统启动时(即执行init.rc时),就会立即启动它。它跑在独立的进程里,其提供IBinder接口,让其它进程里的模块能呼叫之。此刻,言下之意,「它」是主词、是主角,而接口IBinder变成附属的配角了。
就像一个城市,大家关心的是一栋栋的建筑物(实的),而比较忽略街道(虚的)。然而,在西班牙等欧洲地区,其居民就把街与道分开了,道是车辆行走的,而街则是城市的客厅,是城市的主角,而建筑物是配角。因此欧洲城市(如巴塞隆纳、布鲁塞尔等)其外观整齐有致,比东方国家的城市看起来美观多了。
当我们比较重视接口时,就会想去把接口弄得更美观。就像爱漂亮的女生,就会勤于化妆。于是,现在换个观点:
◆ 原来观点:
- IBinder是Google订的,不关我的事。
- 我关心的是如何使用、移植或修改ServiceManager模块。所以对我而言,ServiceManager是主角,而IBinder是配角。
◆ 换个新观点:
- 我是IBinder的设计人,大家可能会认为这是不靠谱的事;没关系只是换个观点而已,何必太务实呢!
- 我关心的是如何设计和包装IBinder接口。所以对我而言,IBinder是主角,而ServiceManager是配角、成千上万个支持IBinder的幕后模块之一。
从上述欧洲的城市之例,大家可以知道,重视虚的街道,让我们扩大视野、心怀整体(整个城市)观,让当地居民自己的生活环境变得优美,也让外来游客络绎不绝。同样地,在Android环境里,重视虚的接口,会让我们扩大视野、心怀整体(整个系统架构)观,让核心服务或HAL驱动开发者更拥有自主性,也让上层AP更容易来与其结合。
2. 以ServiceManager为例
支持C++ Client的需要
于是,就以ServiceManager为例子,由于ServiceManager跑在自己的进程里,为了让别的模块可以来呼叫它的服务,它必需提供IBinder接口,才能让其它进程里的模块来进行IPC沟通。如下图:
图1、凸显IBinder接口
此刻,如果另一个进程里的C++ Client想与ServiceManager互动时,就会透过更底层的ProcesState服务在自己的进程里,诞生一个BpBinder对象,作为BinderDriver的分身(即Proxy对象)。让C++ Client能透过BpBinder而与Binder Driver互动,进而跨进程地与ServiceManager沟通,所以BpBinder也间接地扮演ServiceManager的分身的角色。如下图所示:
图2、Service Manager与其分身(BpBinder)都支持IBinder接口
由于IBinder接口只有一个transact()函数,如果幕后模块(如ServiceManager、CameraService等)想提供更多函数时,就受限于IBinder的单一函数了。此时会让C++ Client觉得很困扰。于是,再加上一个转接器(Adapter)类别:BpServiceManager,其提供较好用的IServiceManager接口。如下图所示:
图3、BpService Manager转接器类别
支持Java Client的需要
刚才是针对C++ 层的Client而进行的接口转换。那么。如果针对Java层的Client时,又如何呢? 如下图所示:
图4、如何服务Java层的Client呢?
此刻,Java Client想与ServiceManager互动时,就会透过JNI Native 函数:BinderInternal.getContxtObject()来做:
- 呼叫底层的ProcesState服务在自己的进程里,诞生一个BpBinder对象,成为C++层的分身。
- 然后呼叫JavaObjectForIBinder()来诞生Java层的分身:BinderProxy类别的对象。如下图所示:
图5、诞生Java层的分身
由于BinderProxy类别的IBinder接口只有一个transact()函数,如果幕后模块(如ServiceManager、SensorService等)想提供更多函数时,就受限于IBinder的单一函数了。此时会让Java Client觉得很困扰。于是,再加上一个转接器(Adapter)类别:ServiceManagerProxy,其提供较好用的IServiceManager接口。[歡迎光臨 高煥堂 網頁: http://www.cnblogs.com/myEIT/ ]
如下图所示:
图6、诞生Java层的Adapter物件
3. 替自己的System Service化妆
上述的接口分身(Proxy)和转接器(Adapter)的基本样式(Pattern),可以应用于你自己开发的系统服务上。例如,一旦你撰写了myLEDService服务,来呼叫HAL层里的LED Driver(或称LED Stub),如下图:
图7、撰写自己的核心服务
如同上述的ServiceManager之例,如果myLEDService类别想提供更多函数时,就受限于IBinder的单一函数了。此时会让Java Client觉得很困扰。于是,再加上一个转接器(Adapter)类别:myLEDService,其提供较好用的ILEDService接口。如下图所示:
图8、让自己的服务更有面子(即接口)
如此,就让让自己的服务更有面子(即更好的接口)了。◆
[Go Back]