点击打开链接
文档目的
在Android手机生产过程中,有时需要做一些器件测试或者其他压力测试,并且保存测试结果,即使手机恢复出场设置或者重新下载版本也不会擦出这些结果,这个时候就要用到NV来保存。本文主要介绍高通平台上层通过调用jni层方法保存NV和读取NV的方法。
java层方法定义
使用高通的工具QXDM连接手机,用NV Browser查看手机的NV数据:
接下来以NVID[02497] Factory Data Storage Area 1为例。
新建一个java文件: NvWriter.java
-
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:
-
NvWriter.getInstance().writeFlagNV(index,NvWriter.PASS);
2.读取NV:
-
NvWriter.getInstance().getFlag(index);
上述方法具体实现都是在jni层,我们接下来看一下jni层是如何实现的。
Jni层方法实现
新建一个cpp文件nvwriter.cpp:
-
#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[n]);
-
}
-
}
-
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中要加入以下语句,不然会编译报错:
-
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
-