Toturial

MTK’s NVRAM realizes data backup and recovery

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


}
Back to top button