MTK平台详解`ro.boot.serialno` 的实现流程 adb devices输出序列号

ro.boot.serialno 实现流程全链路解析

ro.boot.serialno 的传递贯穿设备启动的多个层级,其核心流程可以概括为以下步骤:
Bootloader阶段 Kernel内核参数 Android Init进程 导入内核参数 属性系统初始化 属性映射 ro.serialno属性 设备特定服务 设置sys.serialno 触发属性变更

下面我们来详细看看每个阶段的关键实现。

1. Bootloader阶段:序列号起源

Bootloader(通常是LK,Little Kernel)负责获取或定义初始序列号

  • 关键代码路径

    复制代码
    vendor/mediatek/proprietary/bootable/bootloader/lk/app/mt_boot/mt_boot.c
    vendor/mediatek/proprietary/bootable/bootloader/lk/platform/mtXXXX/mtXXXX.c
  • 序列号来源(MTK平台可能的方式):

    • 从特定存储位置读取:可能是EFUSE、PROINFO分区或安全存储
    • 由制造商烧录工具写入:量产时通过工具写入独立分区
    • 根据硬件信息生成:基于Wi-Fi MAC地址等硬件标识符派生
  • 关键函数调用(具体函数名因平台而异):

    c 复制代码
    // 将序列号添加到内核命令行参数
    snprintf(cmdline + strlen(cmdline), sizeof(cmdline) - strlen(cmdline),
             " androidboot.serialno=%s", serial_number);
2. Kernel阶段:参数接收

内核接收Bootloader传递的参数,但不直接处理 androidboot.serialno,只是将其保存在内核命令行中。

  • 验证命令

    bash 复制代码
    adb shell cat /proc/cmdline | grep -o "androidboot.serialno=[^ ]*"

    预期输出示例:androidboot.serialno=ABCD12345678

3. Android Init进程:属性转换

这是最关键的转换阶段,系统属性在此初始化。

  • 核心代码文件

    复制代码
    system/core/init/init.cpp
    system/core/init/property_service.cpp
    system/core/init/util.cpp
  • process_kernel_cmdline() - 处理内核命令行

    cpp 复制代码
    // system/core/init/init.cpp
    int main(int argc, char** argv) {
        property_init(); // 初始化属性系统
        process_kernel_cmdline(); // 处理内核命令行参数
        // ...
    }
    
    // system/core/init/util.cpp
    static void import_kernel_cmdline(bool in_qemu,
                                    const std::function<void(const std::string&, const std::string&, bool)>& fn) {
        // 读取 /proc/cmdline 并解析,回调 fn 处理每个 key=value 对
    }
    
    static void import_kernel_nv(const std::string& key, const std::string& value, bool for_emulator) {
        if (key == "androidboot.serialno") {
            property_set("ro.boot.serialno", value); // 关键转换!
        }
        // 处理其他参数...
    }
  • export_kernel_boot_props() - 属性映射

    cpp 复制代码
    // system/core/init/init.cpp
    static 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, "");
            // 将 ro.boot.serialno 映射到 ro.serialno
            property_set(prop_map[i].dst_prop, (!value.empty()) ? value : prop_map[i].default_value);
        }
    }
4. 属性系统:只读特性

ro 属性(只读)的特殊处理机制:

  • 代码路径bionic/libc/system_properties/prop_area.cpp
  • ro属性规则
    • 系统启动时只能设置一次
    • 通过 __system_property_find 检查是否已存在,存在则不可修改
    • Init进程在早期拥有设置ro属性的权限
5. 应用层获取

应用通过系统API获取序列号:

  • Java层代码

    java 复制代码
    // frameworks/base/core/java/android/os/Build.java
    public static final String SERIAL = getString("ro.serialno");
    
    // vendor/mediatek/proprietary/packages/apps/MtkSettings/src/com/android/settings/deviceinfo/hardwareinfo/SerialNumberPreferenceController.java
    String serial = Build.SERIAL; // 实际读取的是 ro.serialno
  • Native层获取

    c 复制代码
    #include <sys/system_properties.h>
    char serial_buf[PROP_VALUE_MAX];
    __system_property_get("ro.serialno", serial_buf);

🔧 代码跟踪与Log打印方法

关键日志点

要在代码跟踪时看到相关日志,你可以在以下关键位置添加或查看日志:

阶段 日志位置/方法 关键日志内容
Bootloader LK代码中添加日志或查看Uboot日志 "serialno: ABC123", "cmdline: ... androidboot.serialno=..."
Kernel `adb shell dmesg grep serialno`
Init进程 `adb logcat | grep -iE "(init property)"`
属性系统 `adb logcat grep -i property`
MTK平台专用日志方法

MTK提供了完整的日志抓取系统,可以获取从开机开始的完整日志:

  1. 进入工程模式

    • 拨号盘输入 *#*#3646633#*#**#*#38777#*#*
    • 或者使用 *20121220#
  2. 开启MTKLogger

    bash 复制代码
    # 开启所有日志级别
    adb shell setprop persist.log.tag.all LOGV
    # 或者通过工程模式界面开启MobileLog自动记录
  3. 获取完整启动日志

    • 日志路径:/sdcard/mtklog/mobilelog/APLog_XXXX_XXXX/
    • 关键文件
      • kernel_log.boot - 内核启动日志
      • main_log.boot - Android系统启动日志
      • properties - 系统属性信息
实用调试命令
bash 复制代码
# 查看当前序列号相关属性
adb shell getprop | grep serialno

# 检查内核命令行
adb shell cat /proc/cmdline

# 监控属性变化
adb shell watch getprop | grep serialno

# 获取MTK日志文件
adb pull /sdcard/mtklog/ ./mtklog/

⚠️ 常见问题与调试技巧

  1. 序列号为空或unknown

    • 检查bootloader是否正确传递了参数
    • 确认persist分区或PROINFO分区是否有有效序列号
  2. 属性设置失败

    • 确认只在系统启动早期设置ro属性
    • 检查SELinux策略是否允许属性设置
  3. MTK平台特有问题

    • 某些MTK平台可能使用 ro.boot.sn 而非 ro.boot.serialno
    • 检查 vendor/mediatek/proprietary 下的厂商定制代码

通过以上完整的代码跟踪方案和日志打印方法,你应该能够深入理解MTK平台上 ro.boot.serialno 的完整实现流程。在实际调试中,建议结合MTKLogger获取完整启动日志,这样可以清晰地看到序列号从bootloader到应用层的完整传递过程。

相关推荐
JoyCong19984 小时前
手机、平板、电脑如何投屏画面到电视?ToDesk远程控制TV版教程分享
智能手机·电脑
Digitally12 小时前
如何用5种实用方法将电脑上的音乐传输到安卓手机
android·智能手机·电脑
wanhengidc13 小时前
云手机的基本原理
运维·服务器·游戏·智能手机·云计算
AIminminHu13 小时前
系列文章<八>(从LED显示屏的Gamma过曝问题问题到手机影像):从LED冬奥会、奥运会及春晚等大屏,到手机小屏,快来挖一挖里面都有什么
智能手机·gamma校正·gamma·gamma过曝
飞睿科技20 小时前
超越蓝牙与Wi-Fi,UWB技术如何解锁手机下一波创新浪潮?
嵌入式硬件·物联网·智能手机·uwb
wanhengidc20 小时前
云手机畅玩 梦幻西游
运维·服务器·arm开发·智能手机·自动化
夏婵语冰20 小时前
手机轻松控制电脑:局域网内远程操控B站/抖音实战教程
智能手机·手机轻松控制电脑·局域网内远程操控b站·局域网内远程操控抖音
程序员杰哥20 小时前
Fiddler抓包手机和部分app无法连接网络问题
自动化测试·软件测试·python·测试工具·智能手机·fiddler·测试用例
电化学仪器白超21 小时前
④使用 PPTSYNC.exe 与华为手机拍照制作 GIF 动画
服务器·华为·智能手机