高通平台java层操作NV数据的方法

点击打开链接

文档目的


在Android手机生产过程中,有时需要做一些器件测试或者其他压力测试,并且保存测试结果,即使手机恢复出场设置或者重新下载版本也不会擦出这些结果,这个时候就要用到NV来保存。本文主要介绍高通平台上层通过调用jni层方法保存NV和读取NV的方法。

java层方法定义


使用高通的工具QXDM连接手机,用NV Browser查看手机的NV数据:
高通平台java层操作NV数据的方法
接下来以NVID[02497] Factory Data Storage Area 1为例。

新建一个java文件: NvWriter.java
[java] view plain copy
  1. public class NvWriter {  
  2.     private static final String TAG = "NvWriter-TAG";  
  3.     private static NvWriter sInstance = null;  
  4.   
  5.     /*FLAG RESULT*/  
  6.     public static final char PASS = 'P';  
  7.     public static final char FAIL = 'F';  
  8.     public static final char NA = ' ';  
  9.   
  10.     static {  
  11.       System.loadLibrary("nvwriter_jni");  
  12.     }  
  13.     private native String native_readflag_NV();  
  14.     private native void native_writeflag_NV(int index,char result);  
  15.   
  16.     public static NvWriter getInstance() {  
  17.       if (sInstance == null) {  
  18.         sInstance = new NvWriter();  
  19.       }  
  20.       return sInstance;  
  21.     }  
  22.   
  23.     public String readFlagNV() {  
  24.       String mFlagNv = native_readflag_NV();  
  25.       Log.i(TAG,"readFlagNV: mFlagNv = " + mFlagNv);  
  26.       return mFlagNv;  
  27.     }  
  28.   
  29.     public void writeFlagNV(int index,char result) {  
  30.       native_writeflag_NV(index,result);  
  31.     }  
  32.   
  33.     public char getFlag(int index) {  
  34.       String mFlagNv = readFlagNV();  
  35.       char flag = NA;  
  36.       if (mFlagNv != null && mFlagNv.length() >= index) {  
  37.         flag = mFlagNv.charAt(index);  
  38.       }  
  39.       Log.i(TAG,index + ": flag = " + flag);  
  40.       return flag;  
  41.     }  
  42. }  
高通平台java层操作NV数据的方法
这个类中只有几个简单的方法:
    1.一个单实例的构造方法
    2.3个public的操作NV的java方法
    3.2个native方法
这样我们在需要操作NV的地方,可以像下面这样:
    1.写NV:
[java] view plain copy
  1. NvWriter.getInstance().writeFlagNV(index,NvWriter.PASS);  
高通平台java层操作NV数据的方法
    2.读取NV:
[java] view plain copy
  1. NvWriter.getInstance().getFlag(index);  
高通平台java层操作NV数据的方法

上述方法具体实现都是在jni层,我们接下来看一下jni层是如何实现的。

Jni层方法实现


新建一个cpp文件nvwriter.cpp:
[cpp] view plain copy
  1. #include <unistd.h>  
  2. #include <utils/Log.h>  
  3. #include <cutils/log.h>  
  4. #include <jni.h>  
  5. #include <JNIHelp.h>  
  6. #include <stdlib.h>  
  7. #include "android_runtime/AndroidRuntime.h"  
  8.   
  9. #include <android/log.h>  
  10. #include "nv.h"  
  11. #ifdef LOG_TAG  
  12. #undef LOG_TAG  
  13. #endif  
  14. #define LOG_TAG "NVWriter-TAG-JNI"  
  15. #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)  
  16.   
  17. static int SHOW_LOG = 1; // 1 for show log.  
  18. static int SHOW_NV_LOG = 0; // 1 for show log.  
  19. static const charconst className = "com/xxx/nv/NvWriter";  
  20.   
  21. jint NativeInit() {  
  22.     /* Calling LSM init  */  
  23.     if(!Diag_LSM_Init(NULL)) { // 调用diag初始化  
  24.         LOGI("Diag_LSM_Init() failed.");  
  25.         return -1;  
  26.     }  
  27.   
  28.     LOGI("Diag_LSM_Init succeeded. \n");  
  29.     /* Register the callback for the primary processor */  
  30.     register_callback();  // 注册回调方法  
  31.     return 1;  
  32. }  
  33.   
  34. jstring CharTojstring(JNIEnv* env,const char* str) { // char转化为jstring  
  35.     jsize len = strlen(str);  
  36.     jclass clsstring = env->FindClass("java/lang/String");  
  37.     jstring strencode = env->NewStringUTF("utf-8");  
  38.     jmethodID mid = env->GetMethodID(clsstring,"<init>","([BLjava/lang/String;)V");  
  39.     jbyteArray barr = env->NewByteArray(len);  
  40.     env->SetByteArrayRegion(barr,0,len,(jbyte*)str);  
  41.     return (jstring)env->NewObject(clsstring,mid,barr,strencode);  
  42. }  
  43.   
  44. void android_native_writeflag_NV(JNIEnv *env,jobject this_,jint index,jchar result) { //先读后存  
  45.     if (SHOW_LOG) {  
  46.         LOGI("android_native_writeflag_NV");  
  47.     }  
  48.     if (NativeInit() < 0) {  // 若初始化不成功则直接返回  
  49.         return;  
  50.     }  
  51.     unsigned char tmp[22] = { 0 };  
  52.     unsigned char after[20] = { 0 };  
  53.     nv_items_enum_type nvId = NV_FACTORY_DATA_3_I; // 我们要操作的NVID  
  54.     memset(tmp, 0, sizeof(tmp));   // 申请mem  
  55.     memset(after, 0, sizeof(after));  
  56.     diag_nv_read(nvId,tmp, sizeof(tmp));  // 调用高通操作nv的api,读取NV给tmp  
  57.     for(int m=0;m < sizeof(tmp)-3;m++) {  // 去掉tmp的前三个字段,重新赋值给after  
  58.         if (tmp[m+3] == NULL) {  
  59.             after[m] = ' ';  
  60.         } else {  
  61.             after[m] = tmp[m+3];  
  62.         }  
  63.     }  
  64.     LOGI("android_native_writeflag_NV index = %d\n",(int)index);  
  65.     after[sizeof(tmp)-3+1] = '\0';  
  66.     after[index] = result;  // 把我们要操作的某一位重新赋值  
  67.     if (SHOW_NV_LOG) {  
  68.         for (int n=0;n < sizeof(after);n++) {  
  69.             LOGI("android_native_writeflag_NV,after[%d] = %02x \n",n,after[n]);  
  70.         }  
  71.     }  
  72.     diag_nv_write(nvId,after, sizeof(after));  // 调用高通写nv的api,重新写nv  
  73. }  
  74.   
  75. jstring android_native_readflag_NV(JNIEnv *env) { // 读取nv  
  76.     if (SHOW_LOG) {  
  77.         LOGI("android_native_readflag_NV");  
  78.     }  
  79.     if (NativeInit() < 0) { // 若初始化不成功则直接返回  
  80.         return NULL;  
  81.     }  
  82.     unsigned char tmp[23] = { 0 };  
  83.     unsigned char after[21] = { 0 };  
  84.     memset(tmp, 0, sizeof(tmp));  
  85.     memset(after, 0, sizeof(after));  
  86.     nv_items_enum_type nvId = NV_FACTORY_DATA_3_I;  
  87.     diag_nv_read(nvId,tmp, sizeof(tmp));  // 调用高通操作nv的api,读取NV给tmp  
  88.     for(int m=0;m < sizeof(tmp)-3;m++) {  // 去掉tmp的前三个字段,重新赋值给after  
  89.         if (tmp[m+3] == NULL) {  
  90.             after[m] = ' ';  
  91.         } else {  
  92.             after[m] = tmp[m+3];  
  93.         }  
  94.     }  
  95.     after[sizeof(tmp)-3+1] = '\0';  
  96.     const char* p = (const char*)(char*)after;  
  97.     if (SHOW_NV_LOG) {  
  98.         for(int i=0;i < sizeof(after);i++) {  
  99.             LOGI("android_native_readflag_NV p[%d] = %02x\n",i,p[i]);  
  100.         }  
  101.     }  
  102.   
  103.     jstring flag_string = CharTojstring(env,p);  // char转化为jstring  
  104.     return flag_string;  
  105. }  
  106.   
  107. JNINativeMethod gMethods[] = {  
  108.         { "native_writeflag_NV""(IC)V",(void*) android_native_writeflag_NV },  
  109.         { "native_readflag_NV""()Ljava/lang/String;",(void*) android_native_readflag_NV }  
  110. };  
  111.   
  112. int registerNativeMethods(JNIEnv* env) { //注册方法  
  113.   
  114.     jclass clazz;  
  115.     clazz = env->FindClass(className);  
  116.     if (env->RegisterNatives(clazz, gMethods,  
  117.             sizeof(gMethods) / sizeof(gMethods[0])) < 0) {  
  118.         return -1;  
  119.     }  
  120.     return 0;  
  121. }  
  122.   
  123. jint JNI_OnLoad(JavaVM* vm, void* reserved) {  
  124.     JNIEnv* env = NULL;  
  125.     jint result = -1;  
  126.   
  127.     if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) == JNI_OK) {  
  128.         if (NULL != env && registerNativeMethods(env) == 0) {  
  129.             result = JNI_VERSION_1_4;  
  130.         }  
  131.     }  
  132.     return result;  
  133. }  
高通平台java层操作NV数据的方法
这个cpp要做的事情主要有以下几点:
    1.注册JNI方法
    2.调用高通平台自带的操作nv的方法进行读取和写NV
    3.处理返回的值并传递给java层

有三点需要注意:
    1.diag_nv_read读取返回的nv值前三位要去掉
    2.返回的char要转化为jstring才能传递给上层
    3.nv操作必须要先调用Diag_LSM_Init(NULL)初始化,并register_callback();

总结一下:
由于高通平台自带的源码中就有操作NV的函数,但是是位于cpp中的(vendor/qcom/proprietary/fastmmi和vendor/qcom/proprietary/diag中),但是我们自己的java文件无法直接调用高通的cpp文件,所以我们需要写一个jni文件进行中转。
即:我们的java->我们的jni->高通的cpp
最终实现我们的需求。

最后再注:
在jni文件对应的Android.mk中要加入以下语句,不然会编译报错:
[plain] view plain copy
  1. LOCAL_C_INCLUDES += \  
  2.     vendor/qcom/proprietary/fastmmi/libmmi \  
  3.     external/libcxx/include \  
  4.     external/skia/include/core \  
  5.     external/libxml2/include \  
  6.     external/icu/icu4c/source/common \  
  7.     $(QC_PROP_ROOT)/diag/include \  
  8.     $(QC_PROP_ROOT)/diag/src/ \  
  9.     $(TARGET_OUT_HEADERS)/common/inc  
  10.   
  11. LOCAL_SHARED_LIBRARIES := \  
  12.     libutils \  
  13.     libcutils \  
  14.     libc \  
  15.     libmmi \  
  16.     libdiag  
高通平台java层操作NV数据的方法