Android系统修改 设置->关于平板电脑(手机)->状态信息中显示的SN序列号

本文详细介绍如何在Android系统中定制序列号(SN),包括通过不同方法在kernel层获取序列号,并将其传递给Android层,最终在设备的状态信息中显示。
Android系统修改 设置->关于平板电脑(手机)->状态信息中显示的序列号


1、本文全志A64为例,platform -> sun50iwp1   kernel -> linux-3.10  uboot: uboot-2014.07


---------------------------------kernel层-----------------------------------------------------------

2、由于发现cat /sys/class/android_usb/android0/iSerial的number是等同于android系统状态信息中显示的SN序列号。
   因此在sys_config.fex中又找到以下配置:

;--------------------------------
;---     序列号标志
;--------------------------------
[serial_feature]
sn_filename = "sn.txt"


于是根据子键值名sn_filename 找到位于uboot-2014.07/board/sunxi/common/sunxi_serial.c

int sunxi_set_serial_num(void) 
{
        char serial[128] = {0};
        if(get_serial_num_from_file(serial))           =================> 方法1
        {
                get_serial_num_from_chipid(serial);    =================> 方法2
        }
        printf("serial is: %s\n",serial);
        if(setenv("sunxi_serial", serial))             =================>向kernel env中注册serialno信息
        {
                printf("error:set variable [sunxi_serial] fail\n");
        }


        return 0;
}

sunxi_set_serial_num是获取serialno的函数,其中定义了一个serial数组,而有两种获取serialno的方法;


方法1:
int get_serial_num_from_file(char* serial)
{
		........
		........
		ret = fdt_getprop_string(working_fdt,nodeoffset,"sn_filename",&filename);
        if((ret < 0) || (strlen(filename)== 0) )
        {
                printf("sunxi_serial: sn_filename is not exist\n");
                return -1;
        }
        //check private partition info
        partno = sunxi_partition_get_partno_byname("private");
        if(partno < 0)
        {
                return -1;
        }


        //get data from file
        sprintf(part_info,"%d:0", partno);
        sprintf(addr_info,"%lx", (ulong)serial); 
        sprintf(file_info,"%s", filename);
		
		.........
}


由上可知道方法1的serialno是由以下几部分组成:part_info、addr_info、file_info组成。
(1).通过在private分区中根据子键sn_filename中的值查找device tree获取file_info.
(2).通过强转serial数组的地址作为addr_info.
(3).通过获取private分区的number作为part_info.


方法2:

由上可知道方法2是通过读取特定寄存器的值来作为serialno(20位)。!!!最后通过sunxi_set_serial_num函数中的setenv向kernel env中注册serialno信息。

---------------------------------android层-----------------------------------------------------------

3、内核启动后android启动的第一个进程便是init进程,源码位于system/core/init/init.c中在init.c中,系统从main函数执行。

int main(int argc, char **argv)
{
    ........
	........
	
    property_init();


    get_hardware_name(hardware, &revision);


    process_kernel_cmdline(); ============>关键函数 step1
    ........
}


static void process_kernel_cmdline(void)
{
	/* don't expose the raw commandline to nonpriv processes */
	chmod("/proc/cmdline", 0440);


	/* first pass does the common stuff, and finds if we are in qemu.
	 * second pass is only necessary for qemu to export all kernel params
	 * as props.
	 */
	import_kernel_cmdline(0, ); =============>step2 在此函数中想kernel中获取注册的param 保存到类似ro.boot.xx的字符串中。
	if (qemu[0])
		import_kernel_cmdline(1, import_kernel_nv);


	/* now propogate the info given on command line to internal variables
	 * used by init as well as the current required properties
	 */
	export_kernel_boot_props(); =============>step3 重点关注,对ro.serialno进行赋值
}

static void export_kernel_boot_props(void)
{
    char tmp[PROP_VALUE_MAX];
    char serialno[PROP_VALUE_MAX] = {0}; //add
    int ret;
    unsigned i;
    struct {
        const char *src_prop;
        const char *dest_prop;
        const char *def_val;
    } prop_map[] = {
        { "ro.boot.serialno", "ro.serialno", "", },
        { "ro.boot.mode", "ro.bootmode", "unknown", },
        { "ro.boot.baseband", "ro.baseband", "unknown", },
        { "ro.boot.bootloader", "ro.bootloader", "unknown", },
    };
#####################################################################################################################################################

 
    for (i = 1; i < ARRAY_SIZE(prop_map); i++) { //modfied by tsb  因此此处我把i的值由 0 修改为 1.
					         =====>可以看到通过调用property_get获取ro.boot.xx字符串中的param。
						 =====>然后通过property_set来设置ro.xx字符的param。
#######而对于R58机器而言,不存在以上kernel层1、2步骤,ro.serialno的param来源于调用static int get_chip_id(char *buf, size_t size)函数获取/proc/cpuinfo下的serial号
#######而对于R16机器而言,不存在以上kernel层1、2步骤,ro.serialno的param来源于调用static int get_cpu_id(char* buf, size_t size)函数获取/proc/cpuinfo下的serial号 	
        ret = property_get(prop_map[i].src_prop, tmp);                                                                                                                                           
                                                 =====>!!!!!!!property_set函数只对没有设置过的ro.xx字符串设置param有效。
		                                 =====>!!!!!!!即一个ro.xx字符串一旦被设置过,即再次调用property_set函数无效,本人就在此犯过一次错误!!!!
        if (ret > 0)                             =====>具体可查看property_set实现。
            property_set(prop_map[i].dest_prop, tmp); 
        else
            property_set(prop_map[i].dest_prop, prop_map[i].def_val);
    }

    strlcpy(serialno, "12345678901234597890", sizeof("12345678901234567890"));//add by tsb 自定义serialno 即SN序列号12345678901234567890。
    property_set(prop_map[0].dest_prop, serialno);//add by tsb   设置ro.serialno的值
   
    ..........	
}


4.在frameworks/base/core/java/android/os/Build.java中定义了一个Build类

public class Build
 {   
	.........
	public static final String SERIAL = getString("ro.serialno");
	.........
 }

5.系统设置->关于平板电脑(手机)->状态信息在packages/apps/Settings/src/com/android/settings/deviceinfo/Staus.java进行设置

import android.os.Build; ==>包含了frameworks/base/core/java/android/os/Build.java中定义的一个Build类

public class Status extends PreferenceActivity {

 .........
 
	 protected void onCreate(Bundle icicle) {
			..........
			
			String serial = Build.SERIAL;           ==========>获取字符串
			if (serial != null && !serial.equals("")) {
				setSummaryText(KEY_SERIAL_NUMBER, serial); ===========>设置显示
			} else {
				removePreferenceFromScreen(KEY_SERIAL_NUMBER);
			}
			........
	}
 ...........
}

6.至此,整个流程结束~






                
<think>嗯,用户这次问的是关于MTK平台平板在Meta模式下无法读取SN的问题。从描述看,用户应该是生产线上的技术人员或工程师,遇到了具体的生产测试故障。这类问题通常很紧急,毕竟生产线停摆成本很高。 用户提到两个关键现象:设备管理器显示端口连接正常,但SN读取失败。这说明底层驱动通信是通的,问题可能出在数据解析或设备状态校验环节。考虑到生产环境特殊性,需要优先排查硬件相关因素,比如USB端口供电不稳或数据线质量问题——这在实际产线中很常见。 从技术链路上看,SN读取涉及多个环节:Meta工具→USB驱动→设备预加载程序→NVROM存储区域。其中NVROM损坏的可能性较大,特别是新产线频繁烧录时容易出错。另外注意到用户没提其他测试项是否正常,可能需要提醒用户确认基础通信功能。 软件层面要重点检查三个位置:驱动签名问题(Windows系统常见)、Meta工具配置文件是否包含SN读取权限、设备端预加载程序版本是否匹配。特别是最后一点,MTK不同芯片平台对Meta模式的支持差异很大。 最后建议的解决方案按优先级排列:先换线换端口排除硬件问题,再检查驱动签名和工具配置,最后考虑刷写预加载程序。强制读取NVROM的操作要谨慎,毕竟有损坏风险,但产线上有时不得不这样做。 用户可能还需要知道如何收集日志给MTK技术支持,这部分要准备详细的adb命令。不过回复里已经包含关键指令了,应该够用。 </think> 针对MTK平台平板进入Meta模式后端口连接正常但无法读取序列号SN)的问题,以下是系统化的解决方案: --- ### **故障排查与解决步骤** 1. **检查USB连接与驱动配置** - 更换USB数据线或端口,排除物理连接问题 - 确认设备管理器显示端口为 **`MediaTek USB Port (COMx)`**(非普通ADB端口) - **驱动重置操作**: ```powershell devmgmt.msc # 打开设备管理器 ``` 右键卸载MTK USB驱动 → 拔插设备 → 允许系统自动重装驱动[^1] 2. **验证设备Meta模式状态** - 进入Meta模式的标准操作: **`音量下键 + 电源键`** 长按10秒 → 屏幕全黑且无振动反馈为进入成功 - 使用**工程模式指令**验证连接: ```bash adb devices # 应无设备列表 fastboot devices # 应无响应 ``` 3. **检查SN分区状态** - 通过**MTK专用工具**(如SN Writer工具)检查NVROM分区: ```bash SN_Write_tool.exe --checknvram ``` - 若返回 **`Error 3001: NVRAM corrupt`** → 需重写SN分区 - 若提示 **`Permission denied`** → 设备Bootloader未解锁 4. **重写SN分区流程** 使用**SP Flash Tool**或**SN Writer工具**: 1. 加载对应设备的 **`scatter.txt`** 配置文件 2. 选择 **`NVRAM`** 分区 → 填入正确的16SN码 3. 点击 **`Write`** → 设备**断电状态下**连接电脑 ![SN写入流程示意图](https://example.com/sn_writer_flow.png)[^2] 5. **固件兼容性验证** - 确认使用的 **`预加载软件(Preloader)`** 版本与设备芯片匹配(如MT8768需用**Android 10+版本**) - 下载最新版Meta模式工具包: [MTK_Flash_Tool_v5.2208](https://mtk-driver.com/download/) 6. **强制读取SN的AT指令** 通过串口工具发送底层指令(需Root权限): ```bash echo -e "AT+EGMR=1,7,\"0123456789ABCDEF\"\r" > /dev/ttyMT1 # 写入SN echo -e "AT+EGMR=0,7\r" > /dev/ttyMT1 # 读取验证 ``` --- ### **关键注意事项** - **权限问题**:生产模式下需开启 **`Manufacture APP`** 的SN读写权限(检查 `/system/etc/mddb/` 配置) - **硬件故障**:若多次重写SN失败,检测 **`EEPROM芯片(如24C64)`** 是否损坏 - **日志分析**:抓取Meta模式内核日志 ```bash adb logcat -b kernel | grep "nvram" ``` > **经验提示**:MTK芯片在**低温环境(<5℃)** 下易出现SN读取失败,建议预热设备至15℃以上再操作[^3]。 --- ### **
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

EmbbyDroider

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值