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地址等硬件标识符派生
  • 关键函数调用(具体函数名因平台而异):

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

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

  • 验证命令
    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() - 处理内核命令行

    // 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() - 属性映射

    // 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层代码

    // 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层获取

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

🔧 代码跟踪与Log打印方法

关键日志点

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

阶段日志位置/方法关键日志内容
BootloaderLK代码中添加日志或查看Uboot日志"serialno: ABC123", "cmdline: ... androidboot.serialno=..."
Kerneladb shell dmesg | grep serialno内核启动参数中包含序列号
Init进程`adb logcat | grep -iE "(initproperty)"`
属性系统adb logcat | grep -i property"property_set: ro.serialno"
MTK平台专用日志方法

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

  1. 进入工程模式

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

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

    • 日志路径:/sdcard/mtklog/mobilelog/APLog_XXXX_XXXX/
    • 关键文件
      • kernel_log.boot - 内核启动日志
      • main_log.boot - Android系统启动日志
      • properties - 系统属性信息
实用调试命令
# 查看当前序列号相关属性
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到应用层的完整传递过程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值