android的jni

一、底层实现:

c文件:hardware/libhardware_legacy/power/power.c

以其中set_screen_state(int)函数为例

其Android.mk中添加:
    LOCAL_MODULE:= libpower 编译成lib
    LOCAL_SRC_FILES += power.c

hardware/libhardware_legacy/power/power.c

   1:  int
   2:  set_screen_state(int on) 
   3:  {
   4:      QEMU_FALLBACK(set_screen_state(on));
   5:   
   6:      LOGI("*** set_screen_state %d", on);
   7:   
   8:      initialize_fds();
   9:   
  10:      //LOGI("go_to_sleep eventTime=%lld now=%lld g_error=%s\n", eventTime,
  11:        //      systemTime(), strerror(g_error));
  12:   
  13:      if (g_error)
  14:          goto failure;
  15:   
  16:      char buf[32];
  17:      int len;
  18:      if(on)
  19:          len = snprintf(buf, sizeof(buf), "%s", on_state);
  20:      else
  21:          len = snprintf(buf, sizeof(buf), "%s", off_state);
  22:   
  23:      buf[sizeof(buf) - 1] = '\0';
  24:      len = write(g_fds[REQUEST_STATE], buf, len);
  25:      if(len < 0) {
  26:      failure:
  27:          LOGE("Failed setting last user activity: g_error=%d\n", g_error);
  28:      }
  29:      return 0;
  30:  }

其头文件power.h中:

   1:  #if__cplusplus
   2:  extern "C" {               //注1
   3:  #endif
   4:  enum { 
   5:      PARTIAL_WAKE_LOCK = 1,  // the cpu stays on, but the screen is off
   6:      FULL_WAKE_LOCK = 2  // the screen is also on  
   7:  };
   8:    
   9:  // while you have a lock held, the device will stay on at least at the
  10:  // level you request. 
  11:  int acquire_wake_lock(int lock, const char* id);  
  12:  int release_wake_lock(const char* id);
  13:    
  14:  // true if you want the screen on, false if you want it off   
  15:  int set_screen_state(int on); 
  16:    
  17:  // set how long to stay awake after the last user activity in seconds 
  18:  int set_last_user_activity_timeout(int64_t delay);
  19:    
  20:    
  21:  #if __cplusplus   
  22:  } // extern "C"   
  23:  #endif    

注1:

注1:extern表示其他的类已经定义了这段代码里面的内容,这里只是做声明。
"C”表示的一种编译和连接规约,这里为下一步c++调用其做准备.
比如void foo(int,int);该函数被C编译器编译后在库中的名字为_foo,
而C++编译器则会产生像_foo_int_int之类的名字用来支持函数重载和类型安全连接。
由于编译后的名字不同,C++程序不能直接调用C函数。
因此C++提供了一个C连接交换指定符号extern“C”来解决这个问题而不是一种语言。
C表示这段代码可以是符合C语言的编译和连接规约的任何语言,如Fortran、assembler等。

二、cpp构成jni桥梁

一个CPP文件调用之,则需添加其头文件,比如frameworks/base/core/jni/android_os_Power.cpp.

   1:  #include "JNIHelp.h"
   2:  #include "jni.h"
   3:  #include "android_runtime/AndroidRuntime.h"
   4:  #include <hardware_legacy/power.h>
   5:  namespace android{
   6:  ....
   7:   
   8:      //定义函数:
   9:          static int setScreenState(JNIEnv *env, jobject clazz, jboolean on)
  10:          {
  11:              return set_screen_state(on);//以此实现cpp到c的调用
  12:          }
  13:          
  14:          static JNINativeMethod method_table[] = {//此处实现java对cpp的调用转化 注2
  15:              { "acquireWakeLock", "(ILjava/lang/String;)V", (void*)acquireWakeLock },
  16:              { "releaseWakeLock", "(Ljava/lang/String;)V", (void*)releaseWakeLock },
  17:              { "setLastUserActivityTimeout", "(J)I", (void*)setLastUserActivityTimeout },
  18:              { "setScreenState", "(Z)I", (void*)setScreenState },
  19:              { "shutdown", "()V", (void*)android_os_Power_shutdown },
  20:              { "rebootNative", "(Ljava/lang/String;)V", (void*)android_os_Power_reboot },
  21:          };
  22:          int register_android_os_Power(JNIEnv *env)        //此处注册jni
  23:          {    //向VM(即AndroidRuntime)登记 gMethods[]表格所含的本地函数
  24:              return AndroidRuntime::registerNativeMethods(
  25:                  env, "android/os/Power",
  26:                  method_table, NELEM(method_table));
  27:          }
  28:  };
 注2:

typedef struct {
    const char* name;              //Java中函数的名字
    const char* signature;       //用字符串是描述了函数的参数和返回值       
    void*       fnPtr;             //函数指针,指向C函数
} JNINativeMethod;
其中比较难以理解的是第二个参数,例如
    "()V"
    "(II)V"
    "(Ljava/lang/String;Ljava/lang/String;)V"
    实际上这些字符是与函数的参数类型一一对应的。
    "()" 中的字符表示参数,后面的则代表返回值。例如"()V" 就表示void Func();
    "(II)V" 表示 void Func(int, int);
    具体的每一个字符的对应关系如下
    字符     Java类型     C类型
    V          void           void
    Z          jboolean    boolean
    I          jint        int
    J          jlong       long
    D          jdouble     double
    F          jfloat      float
    B          jbyte       byte
    C          jchar       char
    S          jshort      short
    数组则以"["开始,用两个字符表示
    [I       jintArray      int[]
    [F     jfloatArray    float[]
    [B     jbyteArray    byte[]
    [C    jcharArray    char[]
    [S    jshortArray   short[]
    [D    jdoubleArray double[]
    [J     jlongArray     long[]
    [Z    jbooleanArray boolean[]
    上面的都是基本类型。如果Java函数的参数是class,则以"L"开头,以";"结尾中间是用"/" 隔开的包及类名。而其对应的C函数名的参数则为jobject. 一个例外是String类,其对应的类为jstring
    Ljava/lang/String; String jstring
    Ljava/net/Socket; Socket jobject
    如果JAVA函数位于一个嵌入类,则用$作为类名间的分隔符。
    例如 "(Ljava/lang/String;Landroid/os/FileUtils$FileStatus;)Z"

三、java的封装实现

frameworks/base/core/java/android/os/Power.java        //此处路径跟cpp中注册jni处的路径是一致的.待细研究是否有关系

   1:  package android.os;
   2:  public class Power
   3:  {
   4:          ...
   5:          public static native int setScreenState(boolean on);    //被native修饰的表示调用了非java语言的本地方法
   6:          ...
   7:  }

四、java中对其调用

frameworks/base/services/java/com/android/server/PowerManagerService.java

import android.os.Power;
public class PowerManagerService extends IPowerManager.Stub
       implements LocalPowerManager, Watchdog.Monitor {
        ...
        int err = Power.setScreenState(on);
        ...
}
posted on 2013-12-17 15:30  joseph_伽拉  阅读(4005)  评论(0编辑  收藏  举报