By 高焕堂 2011/09/09  

[ IT史上最完整、最经典的软件框架开发技术宝典 (上百篇经典文章&eBooks) ] 

[ 請指教:高老師的免費on-line教學視頻 ] 

                                                                                                            

[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()来做:

  1. 呼叫底层的ProcesState服务在自己的进程里,诞生一个BpBinder对象,成为C++层的分身。
  2. 然后呼叫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]