• 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
    ", 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] = '';
      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
    ", 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);
            ...
    }
  • 相关阅读:
    分库分表就能无限扩容吗?
    每天数十亿次请求的应用经验分享,值得参考!
    QPS、TPS、并发用户数、吞吐量
    Django优雅集成MongoDB
    Linux apt-get
    Python Tenacity 实现"重试机制"
    Kubernetes 系列(一):Kubernetes 介绍、架构、安装
    MongoDB学习笔记:文档Crud Shell
    ubuntu下快速安装rabbitmq
    Reactor模型详解:单Reactor多线程与主从Reactor多线程
  • 原文地址:https://www.cnblogs.com/joseph-linux/p/3478580.html
Copyright © 2020-2023  润新知