在上一篇文章中,我介绍了一种应用程序直接调用JNI库的HAL设计方法,该方法虽然简单,但是不符合Android的框架结构,下面我们介绍一种通过Service提供接口给应用程序的设计方法,结构如下:

HAL stub <-> JNI 库 <-> JAVA Service <->JAVA 应用程序。

HAL stub的设计和上文一样,JNI库的设计中唯一需要修改的地方就是register_mokoid_server_LedService函数,在上文中该JNI库直接提供给应用程序使用,而这里,JNI库是提供接口给JAVA Service使用,修改如下:


  1. int register_mokoid_server_LedService(JNIEnv* env) { 
  2.     //static const char* const kClassName = 
  3.       //  "com/mokoid/LedClient/LedClient"; 
  4.     static const charconst kClassName = 
  5.         "com/mokoid/server/LedService"
  6.     jclass clazz; 
  7.  
  8.     /* look up the class */ 
  9.     clazz = env->FindClass(kClassName); 
  10.     if (clazz == NULL) { 
  11.         LOGE("Can't find class %s\n", kClassName); 
  12.         return -1; 
  13.     } 
  14.  
  15.     /* register all the methods */ 
  16.     if (env->RegisterNatives(clazz, gMethods, 
  17.             sizeof(gMethods) / sizeof(gMethods[0])) != JNI_OK) 
  18.     { 
  19.         LOGE("Failed registering methods for %s\n", kClassName); 
  20.         return -1; 
  21.     } 
  22.  
  23.     /* fill out the rest of the ID cache */ 
  24.     return 0; 

在这里,我们的JNI库会提供给com.mokoid.server.LedService类使用,而不是上文中的应用程序com.mokoid.LedClient.LedClient类。该JNI库最后会被编译成libmokoid_runtime.so。

下面我们再看看com.mokoid.server.LedService的实现: 


  1. public final class LedService { 
  2.  
  3.     static { 
  4.         System.load("/system/lib/libmokoid_runtime.so"); 
  5.     } 
  6.  
  7.     public LedService() { 
  8.         Log.i("LedService""Go to get LED Stub..."); 
  9.     _init(); 
  10.     } 
  11.  
  12.     /* 
  13.      * Mokoid LED native methods. 
  14.      */ 
  15.     public boolean setOn(int led) { 
  16.         Log.i("MokoidPlatform""LED On"); 
  17.     return _set_on(led); 
  18.     } 
  19.  
  20.     public boolean setOff(int led) { 
  21.         Log.i("MokoidPlatform""LED Off"); 
  22.     return _set_off(led); 
  23.     } 
  24.  
  25.     private static native boolean _init(); 
  26.     private static native boolean _set_on(int led); 
  27.     private static native boolean _set_off(int led); 

这个Service的实现和上文中的应用程序的实现比较类似,也是通过System.load装载JNI库,然后就可以在自己的方法中使用JNI接口,该Service最后会被编译成mokoid.jar,且位于/system/framework中,值得注意的是,应用程序如果要调用该Service,必须在/etc/perimissions中有一个xml文件,内容如下:


  1. xml version="1.0" encoding="utf-8"?> 
  2. <permissions> 
  3.     <library name="com.mokoid.server" 
  4.             file="/system/framework/mokoid.jar"/> 
  5. permissions> 

通过这个文件,应用程序就可以使用com.mokoid.server来找到mokoid.jar文件。

我们最后再来看看应用程序的实现:


  1. package com.mokoid.LedClient; 
  2. import com.mokoid.server.LedService; 
  3.  
  4. import android.app.Activity; 
  5. import android.os.Bundle; 
  6. import android.widget.TextView; 
  7.  
  8. public class LedClient extends Activity { 
  9.     @Override 
  10.     public void onCreate(Bundle savedInstanceState) { 
  11.         super.onCreate(savedInstanceState); 
  12.  
  13.         // Call an API on the library. 
  14.         LedService ls = new LedService(); 
  15.         ls.setOn(1); 
  16.         ls.setOff(2); 
  17.          
  18.         TextView tv = new TextView(this); 
  19.         tv.setText("LED 1 is on. LED 2 is off."); 
  20.         setContentView(tv); 
  21.     } 

这里通过import com.mokoid.server.LedService来使用上面设计的LedService,然后通过new LedService()来得到Service的实例,之后就可以直接调用该Service的方法来控制Led了。

AndroidManifest.xml如下:


  1. <manifest xmlns:android="http://schemas.android.com/apk/res/android" 
  2.     package="com.mokoid.LedClient"> 
  3.      
  4.     <application> 
  5.      
  6.