NV就是Non Volatile缩写,就是非易失性存储性,通俗来说,就是即使系统掉电后,存储在该存储器的数据也不会丢失。
为什么要备份恢复,NV值是需要通过校准和终测才能使手机硬件达到最佳工作状态,特别是其中的RF相关的NV项,经过校准及终测后,每台手机的这些NV值基本上都不一样,又加上NV数据是是存储在镜像文件,而镜像文件数据很可能遭到破坏(如:重新烧写版本),这时的NV数据也将被破坏,之前校准和终测后的NV数据也将无法恢复,使得手机将面临重新走校准、终测的生产流程。
图1-NVRAM框架图
1、frameworks/base/core/java/android/os/NvRAMAgent.java
package android.os;
public interface NvRAMAgent extends IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends Binder implements NvRAMAgent
{
private static final 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(IBinder obj)
{
if ((obj==null)) {
return null;
}
IInterface iin = (IInterface)obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof NvRAMAgent))) {
return ((NvRAMAgent)iin);
}
return new Stub.Proxy(obj);
}
public IBinder asBinder()
{
return this;
}
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws 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 IBinder mRemote;
Proxy(IBinder remote)
{
mRemote = remote;
}
public IBinder asBinder()
{
return mRemote;
}
public String getInterfaceDescriptor()
{
return DESCRIPTOR;
}
public byte[] readFile(int file_lid) throws RemoteException
{
Parcel _data = Parcel.obtain();
Parcel _reply = 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 RemoteException
{
Parcel _data = Parcel.obtain();
Parcel _reply = 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 RemoteException
{
Parcel _data = Parcel.obtain();
Parcel _reply = 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 RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = 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 RemoteException;
public int writeFile(int file_lid, byte[] buff) throws RemoteException;
public byte[] readFileByName(String filepath) throws RemoteException;
public int writeFileByName(String filepath, byte[] buff) throws RemoteException;
}
这个文件是Android上层对nv区的接口文件,里面是都是定义了对nv区的读写函数:readFile(),writeFile(),readFileByName(),writeFileByName()。我们通过调用改接口中的写入函数将我们要写入的数据写入到nv区;调用读取函数读取nv区中的值;nv区的值都是通过类似键值的方式进行存储读写!
2、frameworks/base/core/java/android/os/NvRAMPROINFOUtils.java
package android.os;
/** pro_info cyrus start */
public final class NvRAMPROINFOUtils {
public static final String TAG = "NvRAMPROINFOUtils";
/**
* key: 104-->1024
*/
//add by wst start
public static final int key_fontcamera_value = 668;
public static final int key_backcamera_value = 669;
public static final int read(int key){
int result = 0;
try{
android.os.NvRAMAgent agent = android.os.NvRAMAgent.Stub.asInterface (android.os.ServiceManager.getService("NvRAMAgent"));
result = agent.readFileByName("/data/nvram/APCFG/APRDEB/PRODUCT_INFO")[key];
}catch(Exception e){
}
return result;
}
public static final int read(int key,int signal){
int init_flag = android.os.NvRAMPROINFOUtils.read(key_singal_init);
if(init_flag != 1&&android.os.NvRAMPROINFOUtils.read(key) == 0){
android.os.NvRAMPROINFOUtils.write(key,signal);
android.os.NvRAMPROINFOUtils.write(key_singal_init,1);
return signal;
}else{
return read(key);
}
}
public static final boolean write(int key, int value){
int result = 0;
try{
android.os.NvRAMAgent agent = android.os.NvRAMAgent.Stub.asInterface (android.os.ServiceManager.getService("NvRAMAgent"));
byte[] buff = agent.readFileByName("/data/nvram/APCFG/APRDEB/PRODUCT_INFO");
buff[key] = (byte) value;
result = agent.writeFileByName("/data/nvram/APCFG/APRDEB/PRODUCT_INFO",buff);
}catch(Exception e){
android.util.Log.i("lxm", "NvRAMPROINFOUtils write logstart: " + e.getMessage());
}
return result == 1;
}
}
我们创建的这个文件就是实际操作nv区;我们这里以相机的picturesize的作为例子。我们遇到有些客户要求可以在手机刷机后自己随意选择default picturesize后;在恢复出厂设置后仍然保留之前的设置;我们就可以在相机选择default picturesize时去读取nv区设置的值,来达到打开相机后的default picturesize是之前的值(具体修改camera的picturesize这里就不多介绍了)!