对Android系统的NV区写入配置信息实现手机恢复出厂设置后原有信息不丢失

一、NVRAM基本概念 

NV就是Non Volatile缩写,就是非易失性存储性,通俗来说,就是即使系统掉电后,存储在该存储器的数据也不会丢失。 
为什么要备份恢复,NV值是需要通过校准和终测才能使手机硬件达到最佳工作状态,特别是其中的RF相关的NV项,经过校准及终测后,每台手机的这些NV值基本上都不一样,又加上NV数据是是存储在镜像文件,而镜像文件数据很可能遭到破坏(如:重新烧写版本),这时的NV数据也将被破坏,之前校准和终测后的NV数据也将无法恢复,使得手机将面临重新走校准、终测的生产流程。 

                                                                                             图1-NVRAM框架图 

二、如何实现对NV区的读写操作

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这里就不多介绍了)!

下面是设置 drm_mode_create_dumb 结构体为 NV12 数据的 C 代码示例: ``` #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/ioctl.h> #include <sys/mman.h> #include <drm/drm.h> #include <drm/drm_mode.h> #define ALIGN(val, align) (((val) + (align) - 1) & ~((align) - 1)) int main() { int fd; struct drm_mode_create_dumb create = {0}; struct drm_mode_map_dumb map = {0}; void *ptr; int ret; fd = open("/dev/dri/card0", O_RDWR | O_CLOEXEC); if (fd < 0) { perror("open"); return -1; } // Set width, height and format as per your requirements. create.width = 640; create.height = 480; create.bpp = 12; create.flags = DRM_MODE_CREATE_DUMB_MODE_HINUV; ret = ioctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &create); if (ret < 0) { perror("DRM_IOCTL_MODE_CREATE_DUMB"); return -1; } map.handle = create.handle; ret = ioctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &map); if (ret < 0) { perror("DRM_IOCTL_MODE_MAP_DUMB"); return -1; } ptr = mmap(0, create.size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, map.offset); if (ptr == MAP_FAILED) { perror("mmap"); return -1; } // Fill luma plane with grayscale image uint8_t *luma_ptr = ptr; size_t luma_size = create.width * create.height; memset(luma_ptr, 128, luma_size); // Fill chroma plane with zero uint8_t *chroma_ptr = ptr + ALIGN(luma_size, create.alignment); size_t chroma_size = luma_size / 2; memset(chroma_ptr, 0, chroma_size); // Use the buffer ptr and handle for your further processing return 0; } ``` 在上面的示例中,我们将 `create.flags` 设置为 `DRM_MODE_CREATE_DUMB_MODE_HINUV`,以指示我们将使用 NV12 格式。 然后,我们将 `ptr` 指向内存映射域,并使用 `memset` 函数分别填充亮度和色度平面。 最后,您可以使用 `ptr` 和 `create.handle` 进行您的进一步处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值