在Android中,为了完成上层应用和底层服务之间的相互调用,根据请求的服务不同,交互过程主要有3种类型:直接调用、通过原生服务调用、通过原生守护进程调用。考虑到上层的应用一般是基于Java实现的,而底层服务则是基于C/C++实现的,为了完成跨语言的交互,就需要用到Java JNI机制。
1. Java JNI原生接口
考虑到底层的Linux内核和中间层面的原生服务都是利用C/C++来写的,为了使应用程序能够访问到底层的原生服务和设备,就必须考虑Java和C/C++,甚至汇编语言间的互操作性。在Android中,Java和其他语言的交互是利用Java JNI机制来完成的。
自Java 1.1起,Java JNI(Java Native Interface)标准就已经是Java的一部分,JNI允许Java与其他语言编写的代码进行交互。
Java通过Java JNI调用本地方法,而本地方法是以共享库(*.so)文件的形式存放的,通过调用本地库文件的内部方法,使Java可以实现和本地机器的紧密联系,调用系统级的各接口方法。
在Android中,通过JNIEnv,使得C代码也能调用Java提供的服务,这方面的一个重要实例为IBinder通信。
但需要注意的是,利用C/C++等完成的底层代码的安全性较弱,无法防止开发者利用无效的指针来改写内存,这会导致虚拟机安全性的削弱。
在Android中,原生接口主要位于frameworks\base\core\jni \AndroidRuntime.cpp文件中。利用Java JNI注册原生接口的方法为:
/*static*/ int AndroidRuntime::registerNativeMethods(JNIEnv* env,
const char* className, const JNINativeMethod* gMethods, int numMethods)
{
return jniRegisterNativeMethods(env, className, gMethods, numMethods);
}
2. 直接调用
在直接调用模式中,上层应用通过IBinder机制与框架层的服务直接通信,框架层服务通过Java JNI动态加载相关的共享库,完成服务。
如图1-1所示为上层应用调用硬件抽象层(HAL,Hardware Abstraction Layer)提供的实时服务时的调用层次说明。需要说明的是,HAL的出现更多的是为底层提供封装,保护平台厂商和第三方厂商的利益。

图1-1 实时服务调用层次说明
如图1-2所示为智能手机中常见的位置服务的调用层次说明,上层的导航应用和其他的位置应用在获取底层的GPS服务时,首先调用位置管理器服务(Location Manager Service),然后通过Java JNI终调用libgps.so共享库。

图1-2 位置服务调用层次
3. 原生服务调用
在原生服务调用模式中,由于应用本身更加复杂,应用的抽象实现会放置在原生层,当上层应用调用底层的服务时,首选会通过Java JNI调用应用本身的原生接口,然后通过IPC通信与其他的原生服务进行交互。如图1-3所示为媒体播放应用的调用层次关系。
在多媒体应用中,这是常用的交互方式。

图1-3 原生服务
4.原生守护进程调用
在原生守护进程调用模式中,调用的原生服务通常是后台的守护进程,在这种模式中,上层应用会首先通过Java JNI和应用本身的原生接口通信,然后通过套接字或者IPC和守护进程通信。如图1-4所示为通话应用的调用层次关系。

图1-4 原生守护进程调用