2017年的时候有做过这样的一个定制化需求:写入一个文件数据,恢复出厂设置后该文件数据也要恢复。
第一步:nvram lib id定义
vendor/mediatek/proprietary/custom/project/cgen/inc/Custom_NvRam_LID.h
typedef enum
{
AP_CFG_RDCL_FILE_AUDIO_LID=AP_CFG_CUSTOM_BEGIN_LID, //AP_CFG_CUSTOM_BEGIN_LID: this lid must not be changed, it is reserved for system.
AP_CFG_RDCL_FILE_AUDIO_MAGI_CONFERENCE_LID,
AP_CFG_RDCL_FILE_AUDIO_HAC_PARAM_LID,
AP_CFG_CUSTOM_TEST_CUSTOM1_LID, //zrx add 定义lib id
AP_CFG_CUSTOM_FILE_MAX_LID,
} CUSTOM_CFG_FILE_LID;
//zrx add 添加LID版本信息
#define AP_CFG_CUSTOM_TEST_CUSTOM1_LID_VERNO "000"
第二步:nvram lib id的数据结构和版本号声明
vendor/mediatek/proprietary/custom/project/cgen/inc/Custom_NvRam_data_item.h
//zrx add
LID_BIT VER_LID(AP_CFG_CUSTOM_TEST_CUSTOM1_LID)
Test_Custom1_Struct *CFG_TEST_CUSTOM1_REC_TOTAL
{
};
第三步:nvram lib数据结构定义
vendor/mediatek/proprietary/custom/project/cgen/cfgfileinc/CFG_Custom1_File.h
//zrx add start
typedef struct
{
unsigned char Array[1024];
}Test_Custom1_Struct;
//zrx add end
//zrx add start
#define CFG_TEST_CUSTOM1_REC_SIZE sizeof(Test_Custom1_Struct)
#define CFG_TEST_CUSTOM1_REC_TOTAL 1
//zrx add end
第四步:nvram lib 默认值定义
vendor/mediatek/proprietary/custom/project/cgen/cfgdefault/CFG_Custom1_Default.h
Test_Custom1_Struct stCustom2Default =
{
0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0
};
第五步:nvram lib内容加入nvram数组中
vendor/mediatek/proprietary/custom/m107/cgen/inc/CFG_file_info_custom.h
#include "../cfgfileinc/CFG_Custom1_File.h"
#include "../cfgdefault/CFG_Custom1_Default.h"
const TCFG_FILE g_akCFG_File_Custom[]=
{
{ "/data/nvram/APCFG/APRDCL/Test_Custom1", VER(AP_CFG_CUSTOM_TEST_CUSTOM1_LID), CFG_TEST_CUSTOM1_REC_SIZE,
CFG_TEST_CUSTOM1_REC_TOTAL, SIGNLE_DEFUALT_REC , (char *)&stCustom2Default, DataReset , NULL
},
};
第六步:nvram lib id需要备份到BinRegion
vendor/mediatek/proprietary/external/nvram/libcustom_nvram/CFG_file_info.c
FileName aBackupToBinRegion[]=
{
{"CUSTOM_TEST",AP_CFG_CUSTOM_TEST_CUSTOM1_LID},
}
pfConvertFunc aNvRamConvertFuncTable[]=
{
NULL,//AP_CFG_CUSTOM_TEST_CUSTOM1_LID
}
const TABLE_FOR_SPECIAL_LID g_new_nvram_lid[] =
{
{ AP_CFG_CUSTOM_TEST_CUSTOM1_LID, 1024 * 1024, 1024 * 1024},
};
第七步:上层读写nvram数据接口
NvRAMAgent.java
package com.example.nvram_test;
import android.os.IBinder;
public interface NvRAMAgent extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements NvRAMAgent
{
private static final java.lang.String DESCRIPTOR = "NvRAMAgent";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an NvRAMAgent interface,
* generating a proxy if needed.
*/
public static NvRAMAgent asInterface(android.os.IBinder obj)
{
if ((obj == null)) {
return null;
}
android.os.IInterface iin = (android.os.IInterface) obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof NvRAMAgent))) {
return ((NvRAMAgent) iin);
}
return new NvRAMAgent.Stub.Proxy(obj);
}
public android.os.IBinder asBinder()
{
return this;
}
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
switch (code)
{
case INTERFACE_TRANSACTION:
{
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_READFILE:
{
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
byte[] _result = this.readFile(_arg0);
reply.writeNoException();
reply.writeByteArray(_result);
return true;
}
case TRANSACTION_WRITEFILE:
{
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
byte[] _arg1;
_arg1 = data.createByteArray();
int _result = this.writeFile(_arg0, _arg1);
reply.writeNoException();
reply.writeInt(_result);
return true;
}
default:
{
break;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements NvRAMAgent
{
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
public android.os.IBinder asBinder()
{
return mRemote;
}
public java.lang.String getInterfaceDescriptor()
{
return DESCRIPTOR;
}
public byte[] readFile(int file_lid) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
byte[] _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(file_lid);
mRemote.transact(Stub.TRANSACTION_READFILE, _data, _reply, 0);
_reply.readException();
_result = _reply.createByteArray();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
public int writeFile(int file_lid, byte[] buff) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(file_lid);
_data.writeByteArray(buff);
mRemote.transact(Stub.TRANSACTION_WRITEFILE, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
public byte[] readFileByName(String filename) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
byte[] _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeString(filename);
mRemote.transact(Stub.TRANSACTION_READFILEBYNAME, _data, _reply, 0);
_reply.readException();
_result = _reply.createByteArray();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
public int writeFileByName(String filename, byte[] buff) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeString(filename);
_data.writeByteArray(buff);
mRemote.transact(Stub.TRANSACTION_WRITEFILEBYNAME, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
static final int TRANSACTION_READFILE = (IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_WRITEFILE = (IBinder.FIRST_CALL_TRANSACTION + 1);
static final int TRANSACTION_READFILEBYNAME = (IBinder.FIRST_CALL_TRANSACTION + 2);
static final int TRANSACTION_WRITEFILEBYNAME = (IBinder.FIRST_CALL_TRANSACTION + 3);
}
public byte[] readFile(int file_lid) throws android.os.RemoteException;
public int writeFile(int file_lid, byte[] buff) throws android.os.RemoteException;
public byte[] readFileByName(String filepath) throws android.os.RemoteException;
public int writeFileByName(String filepath, byte[] buff) throws android.os.RemoteException;
}
第八步:读写数据帮助类
Utils.java
ackage com.example.nvram_test;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import android.content.Context;
import android.os.IBinder;
import android.os.ServiceManager;
import android.util.Log;
import android.widget.Toast;
public class Utils {
final String TAG = "Utis";
byte[] buff;
Context mContext;
public Utils(Context mContext){
this.mContext=mContext;
}
/**
* 多个字节数组合并为一个字节数组
* @param a 字节数组
* @param b 字节数组
* @return byte[]
*/
public byte[] combineBytes(byte[] a, byte[] b) {
byte[] bytes = new byte[a.length + b.length];
System.arraycopy(a, 0, bytes, 0, a.length);
System.arraycopy(b, 0, bytes, a.length, b.length);
return bytes;
}
/**
* 写文件到app下
*/
public void writeOwnFile(String fileName,String message){
try {
FileOutputStream fout = mContext.openFileOutput(fileName,
mContext.MODE_PRIVATE);
byte[] bytes = message.getBytes();
fout.write(bytes);
fout.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 从app下读文件
* @param fileName
* @return
*/
public String readOwnFile(String fileName){
try {
FileInputStream fis=mContext.openFileInput(fileName);
ByteArrayOutputStream bos=new ByteArrayOutputStream();
byte[] buffer=new byte[1024];
int len=0;
while((len=fis.read(buffer))!=-1){
bos.write(buff, 0, len);
}
byte[] content_byte = bos.toByteArray();
String content = new String(content_byte);
return content;
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
return null;
}
/**
* 写文件
* @param fileName 文件名
* @param bytes 字节数组
*/
public void writeFile(String fileName,byte[] bytes){
try {
FileOutputStream fout = new FileOutputStream(fileName);
fout.write(bytes);
fout.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 读文件
* @param fileName 文件名
* @return byte[]
*/
public byte[] readFile(String fileName){
try {
FileInputStream fin = new FileInputStream(fileName);
int length = fin.available();
byte [] buffer = new byte[length];
fin.read(buffer);
fin.close();
return buffer;
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
return buff;
}
/**
* 写值到NvRam
* @param file_name NvRam路径
* @param bytes 字节数组
*/
public void writeData(String file_name, byte[] bytes) {
byte[] buff=new byte[1024];
if(bytes.length 0) {
Toast.makeText(mContext, "write Success", Toast.LENGTH_SHORT).show();
// Log.d(TAG, "zrx----write Success");
} else {
Toast.makeText(mContext, "write Failure", Toast.LENGTH_SHORT).show();
Log.d(TAG, "zrx---- write Failure");
}
}
}
/**
* 从NvRam读值
* @param file_name NvRam路径
* @param offset 开始位置
* @param byteCount 字节数
* @return
*/
public byte[] readData(String file_name,int offset,int byteCount) {
byte[] data=new byte[byteCount];
IBinder binder = ServiceManager.getService("NvRAMAgent");
NvRAMAgent agent = NvRAMAgent.Stub.asInterface(binder);
if (agent != null) {
try {
buff = agent.readFileByName(file_name);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
if (buff != null) {
try {
for(int i=0;i
第九步:验证
MainActivity.java
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;
import com.example.nvram_test.R;
public class MainActivity extends Activity{
String TAG="MainActivity";
/**
* 文件名在vendor/mediatek/proprietary/custom/m107/cgen/inc/CFG_file_info_custom.h中有定义
*/
private static final String TEST_FILENAME = "/data/nvram/APCFG/APRDCL/Test_Custom1";
Button btn1;
Button btn2;
Button btn3;
Button btn4;
Utils utils;
/**
* 测试备份SecretKey文件的路径
*/
private static final String secret_filename="/storage/emulated/0/SecretKey";
/**
* 测试备份goc_database文件的路径
*/
private static final String goc_database="/storage/emulated/0/goc_database";
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
utils=new Utils(this);
btn1=(Button)findViewById(R.id.btn1);
btn2=(Button)findViewById(R.id.btn2);
btn3=(Button)findViewById(R.id.btn3);
btn4=(Button)findViewById(R.id.btn4);
/**
* 测试把SecretKey文件的字节备份到NvRam下
*/
btn1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
byte[] a=utils.readFile(secret_filename); //读SecretKey文件
utils.writeData(TEST_FILENAME, a); //把SecretKey文件的字节备份到NvRam下
//byte[] b=utils.readData(TEST_FILENAME, 0, a.length);
/* if(!Arrays.equals(a, b)){
utils.writeData(TEST_FILENAME, a);
}else{
Toast.makeText(MainActivity.this, "SecretKey Data has existed, no need to backup!", Toast.LENGTH_SHORT).show();
}*/
}
});
/**
* 测试从NvRAM读SecretKey文件的字节
*/
btn2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
byte[] bytes=utils.readData(TEST_FILENAME,0,27);//测试从NvRAM读SecretKey文件的字节
Toast.makeText(getApplicationContext(), "data = "+new String(bytes), Toast.LENGTH_LONG).show();
}
});
/**
* 测试写goc_database文件的字节到NvRAM
*/
btn3.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
byte[] bytes=utils.readFile(goc_database); //goc_database文件的字节
byte[] a=utils.readData(TEST_FILENAME,0,27); //读NvRAM下SecretKey文件的字节
utils.writeData(TEST_FILENAME, utils.combineBytes(a, bytes));
}
});
/**
* 测试写到NvRAM下的goc_database文件字节是否与原文件goc_database是否一样。
*/
btn4.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
byte[] bytes=utils.readFile(goc_database); //读goc_database文件
byte[] b=utils.readData(TEST_FILENAME, 27, bytes.length); //读NvRAM下的goc_database字节
utils.writeFile("/storage/emulated/0/goc_database2", b); //把NvRAM下的goc_database字节写到goc_database2文件, goc_database2文件与原文件goc_database比对,发现是相同的。
}
});
}
}