系统获取序列号过程
Android系统的SN号,实际是从“cmdline”里面的“androidboot.serialno”获取到的,那么在给系统传递“cmdline”之前,就需要获取到SN号。
以MTK的一个Android 5.1系统为例,MTK的SN号,通过写号工具,和IMEI等参数,一起写入“NV(Non-Volatile)”中,然后开机再读出来用。
读取SN号的部分,在lk中,代码如下,文件:bootable/bootloader/lk/app/mt_boot/mt_boot.c:
void mt_boot_init(const struct app_descriptor *app)
{
unsigned usb_init = 0;
unsigned sz = 0;
int sec_ret = 0;
#ifdef CONFIG_MTK_USB_UNIQUE_SERIAL
u64 key;
u32 chip_code;
#endif
char serial_num[SERIALNO_LEN];
#ifdef CONFIG_MTK_USB_UNIQUE_SERIAL
/* Please enable EFUSE clock in platform.c before reading sn key */
/* serial string adding */
key = readl(SERIAL_KEY_HI);
key = (key << 32) | readl(SERIAL_KEY_LO);
chip_code = DRV_Reg32(APHW_CODE);
//如果有使用写号工具去写号,那么“key”就不为零,这里具体计算SN号的算法,都是平台厂商定义的东西
//估计是写号的时候,使用逆向的算法得到“key”,读的时候使用“key”再去算SN号
if (key != 0)
get_serial(key, chip_code, serial_num); //这里用到厂商定义的算法,算出来SN号来
else
memcpy(serial_num, DEFAULT_SERIAL_NUM, SN_BUF_LEN); //如果没有写号,使用默认值“DEFAULT_SERIAL_NUM”
/* copy serial from serial_num to sn_buf */
memcpy(sn_buf, serial_num, SN_BUF_LEN); //只需要“SN_BUF_LEN”长度做系统SN号
dprintf(CRITICAL,"serial number %s\n",serial_num);
#else
memcpy(sn_buf, DEFAULT_SERIAL_NUM, strlen(DEFAULT_SERIAL_NUM));
#endif
sn_buf[SN_BUF_LEN] = '\0';
surf_udc_device.serialno = sn_buf;
......
}
读取到SN号之后,传递给“cmdline”的“androidboot.serialno”,代码如下,依然在mt_boot.c文件:
/* Append androidboot.serialno=xxxxyyyyzzzz in cmdline */
sprintf(cmdline, "%s%s%s", cmdline, " androidboot.serialno=", sn_buf);
然后,init进程启动之后,会去处理“cmdline”,得到SN号。
代码如下,文件:system/core/init/init.c
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, import_kernel_nv);
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();
}
void import_kernel_cmdline(int in_qemu,
void (*import_kernel_nv)(char *name, int in_qemu))
{
char cmdline[2048];
char *ptr;
int fd;
fd = open("/proc/cmdline", O_RDONLY);
if (fd >= 0) {
int n = read(fd, cmdline, sizeof(cmdline) - 1);
if (n < 0) n = 0;
/* get rid of trailing newline, it happens */
if (n > 0 && cmdline[n-1] == '\n') n--;
cmdline[n] = 0;
close(fd);
} else {
cmdline[0] = 0;
}
ptr = cmdline;
while (ptr && *ptr) {
char *x = strchr(ptr, ' ');
if (x != 0) *x++ = 0;
import_kernel_nv(ptr, in_qemu);
ptr = x;
}
}
static void import_kernel_nv(char *name, int for_emulator)
{
char *value = strchr(name, '=');
int name_len = strlen(name);
if (value == 0) return;
*value++ = 0;
if (name_len == 0) return;
#ifdef MTK_TC7_COMMON_DEVICE_INTERFACE
if (!strcmp(name,"AdbAutoEnable")) {
char buff[PROP_NAME_MAX];
int len = snprintf( buff, sizeof(buff), "ro.usb.adb.auto_enable" );
if (len < (int)sizeof(buff))
property_set( buff, value );
}
#endif
if (for_emulator) {
/* in the emulator, export any kernel option with the
* ro.kernel. prefix */
char buff[PROP_NAME_MAX];
int len = snprintf( buff, sizeof(buff), "ro.kernel.%s", name );
if (len < (int)sizeof(buff))
property_set( buff, value );
return;
}
if (!strcmp(name,"qemu")) {
strlcpy(qemu, value, sizeof(qemu));
} 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);
}
}
}
在函数“import_kernel_nv”里,获取到“androidboot.serialno”的值,然后设置到系统属性“ro.boot.serialno”,这样Android就获取到了SN号。
客制化序列号
既然知道了SN号的获取流程,那么客制化就可以针对的去修改。
对于Android系统的SN号,只要在设置系统属性“ro.boot.serialno”的时候或之前,进行客制化修改就可以改变系统SN号;
对于fastboot功能的SN号,就要从lk读取SN号的时候,进行对应修改。
比如使用EMMC的id作为SN号,在lk中的修改的话,就要在如下这个位置之前,改变“serial_num”的值。
/* copy serial from serial_num to sn_buf */
memcpy(sn_buf, serial_num, SN_BUF_LEN);
理论上lk这里是可以读EMMC的id的,可以参考preloader中读EMMC的id部分代码,我是在init.c的函数“import_kernel_nv”里实现的,如下:
static void import_kernel_nv(char *name, int for_emulator)
{
......
if (!strcmp(name,"qemu")) {
strlcpy(qemu, value, sizeof(qemu));
} 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)
{
#define EMMC_ID_LEN 32
#define SN_BUF_LEN 10
int fd;
char emmc_id[EMMC_ID_LEN+1];
char sn_buf[SN_BUF_LEN+1];
//如果现在是要处理SN号
if( !strcmp(boot_prop_name,"serialno") )
{
//通过驱动节点读取EMMC的id
fd = open("/sys/block/mmcblk0/device/cid", O_RDONLY);
if (fd < 0)
{
ERROR("can't open: %s\n", "/sys/block/mmcblk0/device/cid");
property_set(prop, value); //打开失败,使用默认值
return;
}
//读取EMMC的id
cnt = read(fd, (void *)&emmc_id, EMMC_ID_LEN);
close(fd);
emmc_id[EMMC_ID_LEN] = 0;
if(cnt != EMMC_ID_LEN)
{
ERROR("read emmc id len error: %d:%d\n", EMMC_ID_LEN, cnt);
property_set(prop, value); //读取不正确,使用默认值
return;
}
//只需要前面10个字符
emmc_id[SN_BUF_LEN] = 0;
cnt = snprintf(sn_buf, sizeof(sn_buf), "%s", emmc_id);
sn_buf[SN_BUF_LEN] = 0;
if(cnt != SN_BUF_LEN)
{
ERROR("set sn buf len error: %d:%d\n", SN_BUF_LEN, cnt);
property_set(prop, value); //长度不正确,使用默认值
return;
}
//使用新SN号设置系统属性
property_set(prop, sn_buf);
}
//如果现在要处理的不是SN号
else
{
property_set(prop, value);
}
}
}
}