您的位置:首页 > 编程语言 > Java开发

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

2017-08-18 14:15 651 查看
点击打开链接


文档目的

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


java层方法定义

使用高通的工具QXDM连接手机,用NV Browser查看手机的NV数据:



接下来以NVID[02497] Factory Data Storage Area 1为例。

新建一个java文件: NvWriter.java

[java] view
plain copy

public class NvWriter {  

    private static final String TAG = "NvWriter-TAG";  

    private static NvWriter sInstance = null;  

  

    /*FLAG RESULT*/  

    public static final char PASS = 'P';  

    public static final char FAIL = 'F';  

    public static final char NA = ' ';  

  

    static {  

      System.loadLibrary("nvwriter_jni");  

    }  

    private native String native_readflag_NV();  

    private native void native_writeflag_NV(int index,char result);  

  

    public static NvWriter getInstance() {  

      if (sInstance == null) {  

        sInstance = new NvWriter();  

      }  

      return sInstance;  

    }  

  

    public String readFlagNV() {  

      String mFlagNv = native_readflag_NV();  

      Log.i(TAG,"readFlagNV: mFlagNv = " + mFlagNv);  

      return mFlagNv;  

    }  

  

    public void writeFlagNV(int index,char result) {  

      native_writeflag_NV(index,result);  

    }  

  

    public char getFlag(int index) {  

      String mFlagNv = readFlagNV();  

      char flag = NA;  

      if (mFlagNv != null && mFlagNv.length() >= index) {  

        flag = mFlagNv.charAt(index);  

      }  

      Log.i(TAG,index + ": flag = " + flag);  

      return flag;  

    }  

}  



这个类中只有几个简单的方法:
    1.一个单实例的构造方法
    2.3个public的操作NV的java方法
    3.2个native方法
这样我们在需要操作NV的地方,可以像下面这样:
    1.写NV:

[java] view
plain copy

NvWriter.getInstance().writeFlagNV(index,NvWriter.PASS);  



    2.读取NV:

[java] view
plain copy

NvWriter.getInstance().getFlag(index);  



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


Jni层方法实现

新建一个cpp文件nvwriter.cpp:

[cpp] view
plain copy

#include <unistd.h>  

#include <utils/Log.h>  

#include <cutils/log.h>  

#include <jni.h>  

#include <JNIHelp.h>  

#include <stdlib.h>  

#include "android_runtime/AndroidRuntime.h"  

  

#include <android/log.h>  

#include "nv.h"  

#ifdef LOG_TAG  

#undef LOG_TAG  

#endif  

#define LOG_TAG "NVWriter-TAG-JNI"  

#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)  

  

static int SHOW_LOG = 1; // 1 for show log.  

static int SHOW_NV_LOG = 0; // 1 for show log.  

static const char* const className = "com/xxx/nv/NvWriter";  

  

jint NativeInit() {  

    /* Calling LSM init  */  

    if(!Diag_LSM_Init(NULL)) { // 调用diag初始化  

        LOGI("Diag_LSM_Init() failed.");  

        return -1;  

    }  

  

    LOGI("Diag_LSM_Init succeeded. \n");  

    /* Register the callback for the primary processor */  

    register_callback();  // 注册回调方法  

    return 1;  

}  

  

jstring CharTojstring(JNIEnv* env,const char* str) { // char转化为jstring  

    jsize len = strlen(str);  

    jclass clsstring = env->FindClass("java/lang/String");  

    jstring strencode = env->NewStringUTF("utf-8");  

    jmethodID mid = env->GetMethodID(clsstring,"<init>","([BLjava/lang/String;)V");  

    jbyteArray barr = env->NewByteArray(len);  

    env->SetByteArrayRegion(barr,0,len,(jbyte*)str);  

    return (jstring)env->NewObject(clsstring,mid,barr,strencode);  

}  

  

void android_native_writeflag_NV(JNIEnv *env,jobject this_,jint index,jchar result) { //先读后存  

    if (SHOW_LOG) {  

        LOGI("android_native_writeflag_NV");  

    }  

    if (NativeInit() < 0) {  // 若初始化不成功则直接返回  

        return;  

    }  

    unsigned char tmp[22] = { 0 };  

    unsigned char after[20] = { 0 };  

    nv_items_enum_type nvId = NV_FACTORY_DATA_3_I; // 我们要操作的NVID  

    memset(tmp, 0, sizeof(tmp));   // 申请mem  

    memset(after, 0, sizeof(after));  

    diag_nv_read(nvId,tmp, sizeof(tmp));  // 调用高通操作nv的api,读取NV给tmp  

    for(int m=0;m < sizeof(tmp)-3;m++) {  // 去掉tmp的前三个字段,重新赋值给after  

        if (tmp[m+3] == NULL) {  

            after[m] = ' ';  

        } else {  

            after[m] = tmp[m+3];  

        }  

    }  

    LOGI("android_native_writeflag_NV index = %d\n",(int)index);  

    after[sizeof(tmp)-3+1] = '\0';  

    after[index] = result;  // 把我们要操作的某一位重新赋值  

    if (SHOW_NV_LOG) {  

        for (int n=0;n < sizeof(after);n++) {  

            LOGI("android_native_writeflag_NV,after[%d] = %02x \n",n,after
);  

        }  

    }  

    diag_nv_write(nvId,after, sizeof(after));  // 调用高通写nv的api,重新写nv  

}  

  

jstring android_native_readflag_NV(JNIEnv *env) { // 读取nv  

    if (SHOW_LOG) {  

        LOGI("android_native_readflag_NV");  

    }  

    if (NativeInit() < 0) { // 若初始化不成功则直接返回  

        return NULL;  

    }  

    unsigned char tmp[23] = { 0 };  

    unsigned char after[21] = { 0 };  

    memset(tmp, 0, sizeof(tmp));  

    memset(after, 0, sizeof(after));  

    nv_items_enum_type nvId = NV_FACTORY_DATA_3_I;  

    diag_nv_read(nvId,tmp, sizeof(tmp));  // 调用高通操作nv的api,读取NV给tmp  

    for(int m=0;m < sizeof(tmp)-3;m++) {  // 去掉tmp的前三个字段,重新赋值给after  

        if (tmp[m+3] == NULL) {  

            after[m] = ' ';  

        } else {  

            after[m] = tmp[m+3];  

        }  

    }  

    after[sizeof(tmp)-3+1] = '\0';  

    const char* p = (const char*)(char*)after;  

    if (SHOW_NV_LOG) {  

        for(int i=0;i < sizeof(after);i++) {  

            LOGI("android_native_readflag_NV p[%d] = %02x\n",i,p[i]);  

        }  

    }  

  

    jstring flag_string = CharTojstring(env,p);  // char转化为jstring  

    return flag_string;  

}  

  

JNINativeMethod gMethods[] = {  

        { "native_writeflag_NV", "(IC)V",(void*) android_native_writeflag_NV },  

        { "native_readflag_NV", "()Ljava/lang/String;",(void*) android_native_readflag_NV }  

};  

  

int registerNativeMethods(JNIEnv* env) { //注册方法  

  

    jclass clazz;  

    clazz = env->FindClass(className);  

    if (env->RegisterNatives(clazz, gMethods,  

            sizeof(gMethods) / sizeof(gMethods[0])) < 0) {  

        return -1;  

    }  

    return 0;  

}  

  

jint JNI_OnLoad(JavaVM* vm, void* reserved) {  

    JNIEnv* env = NULL;  

    jint result = -1;  

  

    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) == JNI_OK) {  

        if (NULL != env && registerNativeMethods(env) == 0) {  

            result = JNI_VERSION_1_4;  

        }  

    }  

    return result;  

}  



这个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

LOCAL_C_INCLUDES += \  

    vendor/qcom/proprietary/fastmmi/libmmi \  

    external/libcxx/include \  

    external/skia/include/core \  

    external/libxml2/include \  

    external/icu/icu4c/source/common \  

    $(QC_PROP_ROOT)/diag/include \  

    $(QC_PROP_ROOT)/diag/src/ \  

    $(TARGET_OUT_HEADERS)/common/inc  

  

LOCAL_SHARED_LIBRARIES := \  

    libutils \  

    libcutils \  

    libc \  

    libmmi \  

    libdiag  

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: