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
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
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
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.
}
});
}
}