android12 NV分区使用简单记录

android12 无法写入NV分区 报错。

2025-05-08 17:00:17.003 10853-10853/? D/NVRAM: NVRAM: NVM_GetLIDByName Lid =77 
2025-05-08 17:00:17.003 10853-10853/? D/NVRAM: fail to open /sys/class/BOOT/BOOT/boot/boot_mode: 
2025-05-08 17:00:17.003 10853-10853/? D/NVRAM: 77 is in new nvram partition!!!
2025-05-08 17:00:17.003 10853-10853/? D/NVRAM: New NVRAM partition name is /dev/block/by-name/proinfo.
2025-05-08 17:00:17.003 10853-10853/? D/NVRAM: RecNum is :1
2025-05-08 17:00:17.005 10853-10853/? D/NVRAM: 77 is in new nvram partition!!!
2025-05-08 17:00:17.006 10853-10853/? D/NVRAM: close File error!
2025-05-08 17:00:17.006 8807-8807/com.android.nvramapp D/NvRamUtils: flag = 0

写入时没有明显的log,就是报错close File error!。

product info 会被 EMMC 写保护挡下 power on write protect权限问题。由于有保护机制,所以取消。
修改的是write_protect_ab.c文件,而不是write_protect.c文件,是因为该项目开启了a/b分区。

vendor/mediatek/proprietary/bootable/bootloader/lk/platform/xxx/write_protect_ab.c
void write_protect_flow(void)
 #endif

        if (!bypass_wp) {
-               ret = set_write_protect();
+               /*ret = set_write_protect();
                if (ret != 0)
-                       pal_log_err("write protect fail! \n");
+                       pal_log_err("write protect fail! \n");*/
                pal_log_err("write protect Done! \n");
        } else
                pal_log_err("Bypass write protect! \n");

以下为简单的NvRamUtils工具类。
由于初始化有一定机率失败,所有多retry几次。


public class NvRamUtils {

    private static final String TAG = "NvRamUtils";

    private static final String PRODUCT_INFO_FILENAME = "/mnt/vendor/nvdata/APCFG/APRDEB" +
            "/xxx";

    /***** NvRamUtils - Place your offset below *****/
    //@Description: Ensure there is no duplicated offset declared!
    // NV offset - Please Try to use the index between 1024 - 2047
    public static final int NV_LENGTH = 1024;

    private static INvram agent;
    private static final int MAX_RETRIES = 10;
    private static final long RETRY_DELAY_MS = 100;

    // 初始化INvram实例
    public static boolean initializeNvramAgent() {
        Log.d(TAG, "inner initializeNvramAgent");
        int retries = 0;
        while (retries < MAX_RETRIES) {
            try {
                Log.d(TAG, "inner initializeNvramAgent INvram getService");
                // 尝试获取服务
                agent = INvram.getService();

                if (agent != null) {
                    Log.i(TAG, "NvramAgent initialized successfully");
                    return true;  // 成功获取到 service,返回 true
                }

                // 如果 agent 为 null,表示获取失败
                Log.e(TAG, "NvramAgent initialization failed, attempt " + (retries + 1) + " of " + MAX_RETRIES);

            } catch (NoSuchElementException e) {
                // 捕获 NoSuchElementException,如果 getService() 返回了 null 或其他问题
                Log.e(TAG, "No such element exception occurred while getting NvramAgent service: " + e.getMessage());
            } catch (RemoteException e) {
                // 处理 RemoteException,通常是与硬件服务通信失败
                Log.e(TAG, "RemoteException while getting NvramAgent service (attempt " + (retries + 1) + " of " + MAX_RETRIES + "): " + e.getMessage());
            }

            retries++;
            // 如果重试次数小于最大次数,等待指定时间后重试
            if (retries < MAX_RETRIES) {
                try {
                    Log.i(TAG, "Retrying to initialize NvramAgent, attempt " + retries + " of " + MAX_RETRIES);
                    TimeUnit.MILLISECONDS.sleep(RETRY_DELAY_MS);  // 等待一段时间后重试
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();  // 恢复中断状态
                    Log.w(TAG, "Thread interrupted during retry sleep", e);
                    return false;  // 如果线程中断,返回失败
                }
            }
        }

        Log.e(TAG, "Failed to initialize NvramAgent after " + MAX_RETRIES + " retries");
        return false;  // 最终失败
    }


    public static byte[] readNvRam(int index, int length) {
        return read(PRODUCT_INFO_FILENAME, index, length);
    }

    public static byte[] read(String filePath, int index, int length) {
        if (agent == null) {
            Log.e(TAG, "NvRamAgent initialization failed");
            return null;
        }
        try {
            StringBuilder nvRamBuf = new StringBuilder();
            if (agent == null) {
                Log.e(TAG, "NvRamAgent is null");
                return null;
            }
            String buff = agent.readFileByName(filePath, index + length);

            Log.i(TAG, "Raw data:" + buff);
            if (buff.length() < 2 * (index + length)) {
                return null;
            }
            // Remove the \0 special character.
            int macLen = buff.length() - 1;
            for (int i = index * 2; i < macLen; i += 2) {
                if ((i + 2) < macLen) {
                    nvRamBuf.append(buff.substring(i, i + 2));
                } else {
                    nvRamBuf.append(buff.substring(i));
                }
            }
            Log.d(TAG, "buff:" + nvRamBuf.toString());
            String str = nvRamBuf.toString();
            return HexDump.hexStringToByteArray(str.substring(0, str.length() - 1));
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }


    public  static boolean writeToNvRam(int index, byte[] buff) {
        return write(PRODUCT_INFO_FILENAME, index, buff);
    }

    /**
     * write a specified byte array into NvRAM, start with the specified index
     *
     * @param index the start position that need to be written
     * @param buff  the values that need to be written from the start position
     * @return true when write succeeded, false when write failed
     */
    public static boolean write(String filePath, int index, byte[] buff) {
        // 检查 agent 是否已经初始化
        if (agent == null) {
            Log.e(TAG, "NvRamAgent is not initialized");
            return false;  // 如果 agent 为 null,说明未初始化,直接返回失败
        }
        try {
            byte[] buffArr = readNvRam(0, NV_LENGTH);
            for (int i = 0; i < buff.length; i++) {
                buffArr[i + index] = buff[i];
            }
            ArrayList<Byte> dataArray = new ArrayList<>(NV_LENGTH);
            for (int j = 0; j < NV_LENGTH; j++) {
                dataArray.add(j, buffArr[j]);
            }
            int flag = agent.writeFileByNamevec(filePath, NV_LENGTH, dataArray);
            Log.d(TAG, "flag = " + flag);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 将字节数组转换为字符串
     */
    public static String byteArrayToString(byte[] byteArray) {
        if (byteArray.length > 0) {
            return String.valueOf(byteArray[0] & 0xFF);  // 转为无符号的字符串
        } else {
            return "0";  // 如果字节数组为空,返回默认值 "0"
        }
    }
}

demo可以参考这个:NvRAM App层的使用

参考链接:
Android系统开发 android8之后版本读写Nvram
Android 9.0 MTK平台Nvram写sn号失败

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容