高通平台java层操作NV数据的方法
2017-08-18 14:15
651 查看
点击打开链接
在Android手机生产过程中,有时需要做一些器件测试或者其他压力测试,并且保存测试结果,即使手机恢复出场设置或者重新下载版本也不会擦出这些结果,这个时候就要用到NV来保存。本文主要介绍高通平台上层通过调用jni层方法保存NV和读取NV的方法。
使用高通的工具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层是如何实现的。
新建一个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
文档目的
在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
相关文章推荐
- 高通平台java层操作NV数据的方法
- 高通平台java层操作NV数据的方法
- Java中最简单的把数据写入xml文件的方法----jdom之xml操作
- 离线轻量级大数据平台Spark之JavaRDD关联join操作
- java 堆 栈 方法区 数据存放 操作流程
- java对前台增删改操作后数据的处理方法
- java 集合框架(TreeSet操作,自动对数据进行排序,重写CompareTo方法)
- Java中最简单的把数据写入xml文件的方法----jdom之xml操作
- Java 操作Excel数据方法
- java中double类型数据加减操作精度丢失问题及解决方法
- java连接redis中的数据查、增、改、删操作的方法
- Java字节流和字符流的区别 (方法区别 操作基本单元区别 操作方式区别 处理数据类型区别) 之个人总结
- JAVA基本数据类型与其他语言数据类型之间的转换方法
- 使用Java操作文本文件的方法详解
- 用JAVA操作数据库Datetime数据
- Java操作文本文件的方法
- Java操作文本文件的方法
- 在java中操作Excel文件的方法
- Java日期操作常用方法(转自 csdn)
- Java日期操作常用方法征集