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.length0) { 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.javaimport 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比对,发现是相同的。 } }); } }