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})$”.