Android设备硬件序列号(SN、串号)分析

Android设备硬件序列号(SN、串号)的序列号是怎么获取的,以全志A64平台来一步步跟代码分析:

在设置-》关于设备-》状态信息中,显示的信息来自android.os.Build.SERIAL,代码位于:
frameworks/base/core/java/android/os/Build.java:
public static final String SERIAL = getString(" ro.serialno ");

frameworks/base/core/java/android/os/Build.java:
private static String getString(String property) {
return SystemProperties.get(property, UNKNOWN);
}

由此可见是通过key为"ro.serialno"的SystemProperties 获取到串号的,接下来看一下ro.serialno是如何赋值的:
先看init代码system/core/init/init.c
int main(int argc, char **argv)
{
.......
property_init();

get_hardware_name(hardware, &revision);

process_kernel_cmdline ();
......

原来是从cmdline中获取的,import_kernel_cmdline把u-boot传给kernel的cmdline进行提取,然后回调import_kernel_nv进行处理
static void process_kernel_cmdline (void)
{
......
import_kernel_cmdline (0, import_kernel_nv);
if (qemu[0])
import_kernel_cmdline(1, import_kernel_nv);
......
export_kernel_boot_props ();
}

import_kernel_nv将cmdline中androidboot.开头的全部转化为"ro.boot.%s"并设置到properties中,例如“androidboot.serialno”为“ro.boot.serialno”:
static void import_kernel_nv(char *name, int for_emulator)
{
......
} else if (!strncmp(name, "androidboot.", 12) && name_len > 12) {
const char *boot_prop_name = name + 12;
char prop[PROP_NAME_MAX];
int cnt;

cnt = snprintf(prop, sizeof(prop), "ro.boot.%s", boot_prop_name);
if (cnt < PROP_NAME_MAX)
property_set (prop, value);
}
}

再来看export_kernel_boot_props函数,将ro.boot.serialno赋值给ro.serialno了
static void export_kernel_boot_props(void)
{
......
} 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 = 0; i < ARRAY_SIZE(prop_map); i++) {
ret = property_get(prop_map[i].src_prop, tmp);
if (ret > 0)
property_set (prop_map[i].dest_prop, tmp);
else
property_set(prop_map[i].dest_prop, prop_map[i].def_val);
}

再来看看u-boot是如何获取串号的:
u-boot-2014.07/common/cmd_boota.c中有对androidboot.serialno的赋值:
void update_bootargs(void)
{
......
//serial info
str = getenv(" sunxi_serial ");
sprintf(tmpbuf," androidboot.serialno =%s",str);
......
}

其值来自于u-boot env sunxi_serial,sunxi_serial又是由DTS中的/soc/serial_feature定义的,由sys_config.fex转换的dts内容,sn.txt又是放在private分区中。
[serial_feature]
sn_filename = "sn.txt"

int sunxi_set_serial_num(void)
{
char serial[128] = {0};
if( get_serial_num_from_file (serial))
{
get_serial_num_from_chipid(serial);
}
printf("serial is: %s\n",serial);
if(setenv(" sunxi_serial ", serial))
{
printf("error:set variable [sunxi_serial] fail\n");
}
return 0;
}

就用private分区存放sn.txt这种方式来验证一下:
busybox mkfs.vfat /dev/block/by-name/private
busybox mount -t vfat /dev/block/by-name/private /private/
echo "XXXX2017030219360001">/private/sn.txt
sync

重启系统,发现串号变成了我们sn.txt里面的内容,重新刷机验证序列号没有被清掉。

另外根据android兼容说明,串号必须满足以下要求(主要是 6~20长度的ASSCII编码字符
A hardware serial number, which MUST be available and unique
across devices with the same MODEL and MANUFACTURER. The
value of this field MUST be encodable as 7-bit ASCII and match the
regular expression “^([a-zA-Z0-9]{6,20})$”.

猜你喜欢

转载自blog.csdn.net/dpppppp/article/details/79353297