android的jni

1、底層實現:

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

以其中set_screen_state(int)函數爲例html

其Android.mk中添加:
    LOCAL_MODULE:= libpower 編譯成lib
    LOCAL_SRC_FILES += power.c
java

hardware/libhardware_legacy/power/power.candroid

   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中:c++

   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等。安全

2、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"ui

3、java的封裝實現

frameworks/base/core/java/android/os/Power.java        //此處路徑跟cpp中註冊jni處的路徑是一致的.待細研究是否有關係spa

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

4、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);
        ...
}
相關文章
相關標籤/搜索