In 2017, there was such a customized requirement: write a file data, and the file data also needs to be restored after restoring the factory settings.
Step 1: nvram lib id definition
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 defines lib id AP_CFG_CUSTOM_FILE_MAX_LID, } CUSTOM_CFG_FILE_LID; //zrx add Add LID version information #define AP_CFG_CUSTOM_TEST_CUSTOM1_LID_VERNO "000"
Step 2: declare the data structure and version number of 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 { };
Step 3: nvram lib data structure definition
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
Step 4: nvram lib default value definition
vendor/mediatek/proprietary/custom/project/cgen/cfgdefault/CFG_Custom1_Default.h
Test_Custom1_Struct stCustom2Default = { 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 };
Step 5: Add the contents of nvram lib to the nvram array
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 }, };
Step 6: nvram lib id needs to be backed up to 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}, };
Step 7: Upper layer read and write nvram data interface
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; }
Step 8: Read and write data helper class
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; } /** * Combine multiple byte arrays into one byte array * @param a byte array * @param b byte array * @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; } /** * Write files to 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(); } } /** * Read files from 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; } /** * write file * @param fileName file name * @param bytes byte array */ public void writeFile(String fileName,byte[] bytes){ try { FileOutputStream fout = new FileOutputStream(fileName); fout.write(bytes); fout.close(); } catch (Exception e) { e.printStackTrace(); } } /** * Read file * @param fileName file name * @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; } /** * Write value to NvRam * @param file_name NvRam path * @param bytes byte array */ public void writeData(String file_name, byte[] bytes) { byte[] buff = new byte[1024]; if(bytes.length<buff.length){ for(int="" i="0;i<bytes.length;i++){" buff[i]="bytes[i];" }="" *for(int="" j="bytes.length;j<buff.length;j++){" buff[j]="(byte)0;" }*="" }else{="" ibinder="" binder="ServiceManager.getService("NvRAMAgent");" nvramagent="" agent="NvRAMAgent.Stub.asInterface(binder);" if="" (agent="" !="null)" {="" int="" flag="0;" try="" buff);="" catch="" (exception="" e)="" todo:="" handle="" exception="" e.printstacktrace();="" (flag="">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"); } } } /** * Read value from NvRam * @param file_name NvRam path * @param offset starting position * @param byteCount number of bytes * @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<bytecount;i++){ data[i]="buff[offset+i];" }="" catch="" (exception="" e)="" {="" todo:="" handle="" exception="" e.printstacktrace();="" return="" data;="" <="" pre="">
Step 9: Verify
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"; /** * The file name is defined in 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; /** * Test the path to the backup SecretKey file */ private static final String secret_filename="/storage/emulated/0/SecretKey"; /** * Test the path to the backup goc_database file */ 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); /** * Test the backup of the SecretKey file bytes to NvRam */ btn1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View arg0) { // TODO Auto-generated method stub byte[] a=utils.readFile(secret_filename); //Read SecretKey file utils.writeData(TEST_FILENAME, a); //Back up the bytes of the SecretKey file to 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(); }*/ } }); /** * Test reading the bytes of the SecretKey file from NvRAM */ btn2.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View arg0) { // TODO Auto-generated method stub byte[] bytes=utils.readData(TEST_FILENAME,0,27); //Test the bytes of the SecretKey file read from NvRAM Toast.makeText(getApplicationContext(), "data = "+new String(bytes), Toast.LENGTH_LONG).show(); } }); /** * Test to write bytes of goc_database file to NvRAM */ btn3.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View arg0) { // TODO Auto-generated method stub byte[] bytes=utils.readFile(goc_database); //bytes of goc_database file byte[] a=utils.readData(TEST_FILENAME,0,27); //Read the bytes of the SecretKey file in NvRAM utils.writeData(TEST_FILENAME, utils.combineBytes(a, bytes)); } }); /** * Test whether the bytes of the goc_database file written to NvRAM are the same as the original file goc_database. */ btn4.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View arg0) { // TODO Auto-generated method stub byte[] bytes=utils.readFile(goc_database); //Read goc_database file byte[] b=utils.readData(TEST_FILENAME, 27, bytes.length); //Read goc_database bytes under NvRAM utils.writeFile("/storage/emulated/0/goc_database2", b); //Write the goc_database bytes under NvRAM to the goc_database2 file. Compare the goc_database2 file with the original file goc_database and find that they are the same. } }); } }