🔍 ro.boot.serialno 属性传递链
ro.boot.serialno 的传递主要经过以下阶段,你可以循着这个路径在代码中跟踪:
Bootloader阶段 Kernel内核参数 Android Init进程 导入内核参数 属性系统初始化 属性映射 ro.serialno属性 设备特定服务 设置sys.serialno 触发属性变更
1. Bootloader阶段
Bootloader(如U-Boot)负责获取或定义初始序列号。
- 在一些平台(如Rockchip),U-Boot可能从特定存储位置 (如IDBLOCK_SN偏移地址)读取序列号,然后将其设置到环境变量
fbt_sn#,再传递到androidboot.serialno。 - 在高通平台,代码(如
update_cmdline函数)会将usb_sn_cmdline(即 "androidboot.serialno=")与sn_buf(序列号值)拼接至内核命令行 。 - 序列号也可能由制造商烧录工具 写入设备闪存的独立分区 (如
sn.txt文件),Bootloader再从中读取 。
2. Kernel内核参数
- Bootloader将序列号作为
androidboot.serialno参数附加到内核命令行。 - 系统启动后,你可通过
cat /proc/cmdline查看所有内核参数,其中应包含androidboot.serialno=你设备的序列号。
3. Android Init进程
Android系统初始化时,init 进程负责解析内核命令行并设置初始属性。
-
导入内核参数 :在
system/core/init/init.cpp的main()函数中,会调用process_kernel_cmdline()函数 。该函数通过import_kernel_cmdline函数解析/proc/cmdline,并回调import_kernel_nv函数来提取androidboot.serialno参数,然后将其设置到ro.boot.serialno系统属性 。 -
属性系统初始化与映射 :属性系统初始化后,
init进程会调用export_kernel_boot_props()函数。此函数包含一个属性映射表 ,将ro.boot.serialno的值映射到ro.serialno属性 (如果ro.boot.serialno有值)。部分代码示例如下:cppstatic void export_kernel_boot_props() { struct { const char *src_prop; const char *dst_prop; const char *default_value; } prop_map[] = { { "ro.boot.serialno", "ro.serialno", "" }, // 映射序列号 // ... 其他属性映射 }; for (size_t i = 0; i < arraysize(prop_map); i++) { std::string value = GetProperty(prop_map[i].src_prop, ""); property_set(prop_map[i].dst_prop, (!value.empty()) ? value : prop_map[i].default_value); } }此映射关系也在其他代码分析中得到确认 。
4. 属性映射与触发设置(备选路径)
-
在某些情况下(如RK3368平台),若未通过内核命令行设置,序列号可能通过设备特定服务 (如
drmservice)设置。该服务可能从ID块读取或根据Wi-Fi MAC地址等生成序列号,然后设置sys.serialno属性。init进程的.rc脚本(如init.rk30board.rc)可监听sys.serialno的变化,并据此设置ro.serialno:rcon property:sys.serialno=* setprop ro.serialno ${sys.serialno}
5. 应用层获取
应用层通过 android.os.Build.SERIAL 获取的序列号,最终来源于 ro.serialno 系统属性 。
java
// frameworks/base/core/java/android/os/Build.java
public static final String SERIAL = getString("ro.serialno");
🔬 代码跟踪与调试方法
关键代码文件
- Bootloader (U-Boot) :查找设置
androidboot.serialno的命令行参数代码,通常在涉及序列号初始化或命令行构建的文件中(如update_cmdline函数 )。 - Android Init 进程 :
system/core/init/init.cpp:关注main()函数,特别是process_kernel_cmdline()和export_kernel_boot_props()的调用 。system/core/init/property_service.cpp:包含属性设置相关逻辑。
- 系统属性 :
bionic/libc/include/sys/_system_properties.h等文件包含系统属性API。
实用调试命令
-
检查内核命令行:
bashadb shell cat /proc/cmdline查找
androidboot.serialno=条目 。 -
查看系统属性:
bashadb shell getprop | grep serialno重点关注
ro.boot.serialno和ro.serialno的值 。 -
查看系统属性设置调用栈(需系统权限或DEBUG版本):
- 在
property_set函数(或在Android 8.0及更高版本中的相应函数)添加日志或设置断点。 - 使用
adb logcat查看init进程的详细日志输出(可能需要DEBUG版本)。
- 在
MTK平台的补充说明
在MTK平台(如Android R),ro.boot.serialno 同样从Uboot传递 。关键映射过程在 export_kernel_boot_props 中完成。MTK的 Settings 应用和 DeviceIdentifiersPolicyService 会读取 ro.serialno 或 ro.boot.serialno 。
💎 核心步骤总结
跟踪 ro.boot.serialno 的实现,关键在于理解其传递链:
- 起始:序列号源于Bootloader(从存储或环境变量获取,或由工具写入)。
- 传递 :通过内核命令行参数
androidboot.serialno传递给内核 。 - 转换 :Android
init进程解析该参数,将其设置为ro.boot.serialno属性,进而映射到ro.serialno。 - 应用 :应用层通过
android.os.Build.SERIAL(即ro.serialno)读取 。
希望这份详细的代码跟踪指南能帮助你深入理解 ro.boot.serialno 的实现。如果你在具体的代码跟踪过程中遇到问题,比如在某个环节找不到预期的代码,欢迎随时提出。