何为定制Android系统?就是在特定的硬件上,移植上Android操作系统,并修改原生Android系统以提供给定制的APP操作定制硬件的方法。
所以,定制Android的主要工作有以下三部分:
- 适配硬件;
- 制作接口;
- 定制APP;
一般而言,定制的硬件会采用方案商提供的稳定方案,例如全至的a20方案、a31s方案、r16方案、飞思卡尔的i.MX6方案等等。这些方案拿过来,是一个类似于平板的开发板,在其上Android系统是能够跑起来的。然后就要根据自身的需求,把一些外围硬件适配上去,例如你要做一个音箱类的产品,你可能需要适配上牛掰的DSP,PA等等,如果你要做一个车机类的产品,你可能要适配上一个MCU,适配上倒车摄像头,如果是要做一个电视盒子,红外或者2.4g是必须的。这就是适配硬件所要做的工作。
定制的硬件产品一般都会应用于一些特殊的场景下,那么肯定会需要定制一个APP来和用户进行交互,完成用户所需要的功能。因为硬件是定制的,很多功能原生的Android系统并没有提供接口来操作,这就需要开发人员对Android进行修改,把操作硬件的方法暴露给APP。这就是我所做的工作。这部分的工作处于应用开发和驱动开发之间,我姑且称之为Android中间件的开发。
开发驱动的同事一般会提供给我一些设备节点,通过读写这些设备节点就可以操作外设。一般来说,操作设备节点的操作会用C/C++来实现。但是对于制作APP的同事,他们会习惯于使用Java这类高级语言,所以对于Android中间件的开发者,就要借助于JNI这一工具,构建连接C/C++和Java的桥梁。
在我的开发过程中,我使用过以下几种方法来提供操作硬件的接口:
- 提供JNI源代码;
提供JNI源代码是最裸的一种方式。一般在调试一个硬件功能的时候,我会编写一个简单的Demo APP。调试成功之后,我曾直接把Demo APP的源代码提供给APP开发者。这样,我的工作是最少的,只要调试完,就算是大功告成了。但是对于开发APP的同事来说,这种提供接口的方式需要他们具备一定的JNI开发知识,这就无形中增加了他们的工作量。在我看来,APP开发应该讲经历集中于与用户的交互上,而不是具体的功能的实现细节上。所以这种方法并不好。
另外一方面,因为接口的源代码文件肯定不止一个,那么源代码的版本控制也是一个问题。
- 提供JNI编译的库文件;
具体来说,提供库文件有两种方式。一种是给APP提供JNI编译之后的库文件,由他们集成到APP中。这种方式只是简化了版本控制的问题(因为只有一个库文件),对APP开发者的要求没有减少。另一种是把JNI在源代码的环境中编译,编译完之后库文件就在/system/lib/下面了。APP只需运行在特定固件中就行了。这种方式的版本控制问题更严重。因为采用这种方式,在库函数载入的时候会检查APP中声明的接口函数是否和当前库中的函数一一对应,不对应会直接崩掉。所以,如果在某个版本之后,APP新增了一个接口,那么这个新的APP就不能运行在老的固件中了。
- 编写后台运行的服务;
为了解决上面的问题,可以编写一个Service。由这个Service来和APP进行交互。因为Service是内置在固件内部的,所以这个Service和JNI不会有版本匹配的问题。而且交互的过程全部都是通过Java实现的(APP开发者最开心了)。APP和Service是运行与不同进程中的,Android的IPC一般有两种方式,一种是通过系统广播,一种是通过AIDL。前者的优点是使用简单,调用不同的接口只需发送不同的广播就行了,返回值则通过接收广播来获取。它的缺点通过广播调接口的实时性不能保证。后者则编写难度较大。各位可以找一下远程服务的代码看看,为了调一个接口,需要编写很多行的代码,这个也是APP的开发人员不想看到的。
其实IPC还有另外一种方式,就是通过socket。这种方式我没有用过,因为其代码编写的量也不少。
- 增加系统服务;
这种方式在我目前看来,是最好的方法。为什么好呢?下次再说。已经快一点了,明天还要上班。