一、A33 Android4.4 设备序列号

A33 Android4.4平台的序列号,可以通过设置->关于平板电脑->状态信息→序列号 进行查看,也可以通过adb指令getprop ro.serialno 进行查看。

A33 Android4.4固定序列号的方法为通过获取CPU串号,根据CPU串号换算出一个设备序列号,再写入到设备里,具体的源码如下:

system/core/init/init.c
 
static void export_kernel_boot_props(void)
{
    char tmp[PROP_VALUE_MAX];
    char cpuinfobuf[1024] = {0};
    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", },
    };
 
    get_cpu_id(cpuinfobuf, sizeof(cpuinfobuf));//louhn:获取CPU串号
    i = 0;
    property_set(prop_map[i].dest_prop, cpuinfobuf); //louhn:根据CPU串号设置ro.serialno
    for (i = 1; 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);
    }
 
    ret = property_get("ro.boot.console", tmp);
    if (ret)
        strlcpy(console, tmp, sizeof(console));
    ... ...
}

二、A33 Android6.0/MS8909 Android7.1 设备序列号

A33 Android6.0/MS8909 Android7.1平台的序列号,可以通过设置->关于平板电脑->状态信息→序列号 进行查看,也可以通过adb指令getprop ro.serialno 进行查看。

A33 Android6.0/MS8909 Android7.1固定序列号的方法为通过获取ro.boot.serialno的值,如果ro.boot.serialno的值存在则把这个值也赋给 ro.serialno,如果不存在,则为空

而ro.boot.serialno的值是在uboot上通过getenv("sunxi_serial")获取的

具体的源码如下:

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",   "", },
        { "ro.boot.mode",       "ro.bootmode",   "unknown", },
        { "ro.boot.baseband",   "ro.baseband",   "unknown", },
        { "ro.boot.bootloader", "ro.bootloader", "unknown", },
        { "ro.boot.hardware",   "ro.hardware",   "unknown", },
        { "ro.boot.revision",   "ro.revision",   "0", },
    };
    for (size_t i = 0; i < ARRAY_SIZE(prop_map); i++) {
        char value[PROP_VALUE_MAX];
        int rc = property_get(prop_map[i].src_prop, value);
        property_set(prop_map[i].dst_prop, (rc > 0) ? value : prop_map[i].default_value);//如果ro.boot.serialno有值,则把这个值赋给ro.serialno,而ro.boot.serialno是从uboot上的cmdline里的androidboot.serialno获取的
    }
}

由于A33 Android6.0系统有出现serialno相同的情况,这里我对serialno的设定进行了修改,与A33 Android4.4保持一致,用CPU串号去固定serialno,修改方法如下:

diff --git a/android/system/core/init/init.cpp b/android/system/core/init/init.cpp
index 671580a003..8169fbda01 100755
--- a/android/system/core/init/init.cpp
+++ b/android/system/core/init/init.cpp
@@ -794,6 +794,8 @@ static void import_kernel_nv(char *name, bool for_emulator)
 }
 
 static void export_kernel_boot_props() {
+    char cpuinfobuf[1024] = {0};
+    size_t i = 0,len = 0,j = 0;
     struct {
         const char *src_prop;
         const char *dst_prop;
@@ -806,7 +808,35 @@ static void export_kernel_boot_props() {
         { "ro.boot.hardware",   "ro.hardware",   "unknown", },
         { "ro.boot.revision",   "ro.revision",   "0", },
     };
-    for (size_t i = 0; i < ARRAY_SIZE(prop_map); i++) {
+    i = 0;
+    FILE *fp = fopen("/proc/cpuinfo", "r");  //从cpuinfo里获取cpu串号,并把串号赋值给cpuinfobuf
+    if(NULL != fp)
+    {
+     
+        while(!feof(fp))
+        {
+            memset(cpuinfobuf,0, sizeof(cpuinfobuf));
+            fgets(cpuinfobuf,sizeof(cpuinfobuf)-1, fp);
+            if(strstr(cpuinfobuf,"Serial"))
+            {
+                    while(cpuinfobuf[len++] != ':');
+                    len++;
+                    while(cpuinfobuf[len])
+                    {
+                        cpuinfobuf[j++] = cpuinfobuf[len++];
+                    }
+                    cpuinfobuf[j] = '\0';
+                    break; 
+            }
+        }
+        fclose(fp);
+    }
+    else
+    {
+        printf("failed to open cpuinfo\n");
+    }
+    property_set(prop_map[i].dst_prop, cpuinfobuf);
+    for (i = 1; i < ARRAY_SIZE(prop_map); i++) {
         char value[PROP_VALUE_MAX];
         int rc = property_get(prop_map[i].src_prop, value);
         property_set(prop_map[i].dst_prop, (rc > 0) ? value : prop_map[i].default_value);

 

三、RK3288/RK3399 Android7.1 设备序列号

RK3288/RK3399 Android7.1平台的序列号,可以通过设置->关于设备->状态信息→序列号 进行查看,也可以通过adb指令getprop ro.serialno 进行查看。

RK3288/RK3399 Android7.1固定序列号的方法为通过获取wifi模块的序列号,再把该序列号赋值给sys.serialno,sys.serialno的值再赋给ro.serialno,具体的源码如下:

1.system/core/drmservice/drmservice.c

在main函数下的generate_device_serialno函数里面,会去获取serialno赋给sn_buf_auto,

generate_device_serialno函数里有个 if(!get_serialno_cached(result,len))判断,该判断意思就是:如果有生成/data/misc/wifi/serialno这个文件,就直接return,如果没有这个文件,程序就往下执行,生成一串值赋值给/data/misc/wifi/serialno

void generate_device_serialno(int len,char*result)
{
	int temp=0,rand_bit=0,times =0;
	int fd,type;
	char buf[32];
	char value[6][2];
	const char *bufp;
	ssize_t nbytes;
	char path[64];
	unsigned int seed[2]={0,0};

	#ifdef DEBUG_RANDOM
		SLOGE("-------DEBUG_RANDOM mode-------");
		goto bail;
	#endif
	
	if(!get_serialno_cached(result,len))
	{
		SLOGE("----------serianno =%s",result);
		return;
	}

	if(check_wlan_mac()<0)//not buffered in data,do it
	{		
		fd = open(WIFI_MAC_FILENAME, O_RDONLY);//read form buffered file
		if(fd<0)
		{
			if(DEBUG_LOG)
				SLOGE("---------------can not access %s,try to insmod wifi and try again\n",WIFI_MAC_FILENAME);
       		
			type = RK903;//check_wifi_chip_type();
			if(type == MT6620)
			{
				if(DEBUG_LOG)
					SLOGE("------------check_wifi_chip_type = MT6620\n");
				insmod("/system/lib/modules/mtk_hif_sdio.ko");
				insmod("/system/lib/modules/mtk_stp_wmt.ko");
				insmod("/system/lib/modules/mtk_stp_uart.ko");
				insmod("/system/lib/modules/mtk_wmt_wifi.ko");
				insmod("/system/lib/modules/hci_stp.ko");
				insmod("/system/lib/modules/wlan.ko");
				
				system("setprop ctl.start 6620_launcher");
				system("setprop ctl.start netd");
				usleep(150000);
				system("setprop ctl.start hald");
				system("echo 1 > /dev/wmtWifi");
				usleep(150000);
				system("setprop ctl.start wpa_supplicant");
			}
			else
			{
				if(DEBUG_LOG)
					SLOGE("------------check_wifi_chip_type != MT6620\n");
				if(wifi_load_driver()!=0)//use interface provided by libhardware_legacy
				{
					srand(time(0));
					if(DEBUG_LOG)
						SLOGE("------------open file failed,and try insmod wifi failed,SLOGE=%s\n",strerror(errno));
					goto bail;
				}
			}
			
		}
		SLOGE("------------ set_iface ----------------");
		set_iface("wlan0", 1);
		store_wlan_mac();//buffer mac to data
		set_iface("wlan0", 0);
	}
	
	fd = open(WLAN_MAC_FILE, O_RDONLY);

	if(fd<0)
	{
		srand(time(0));
		if(DEBUG_LOG)
			SLOGE("------------wifi mac has been cached ,but open failed,SLOGE=%s\n",strerror(errno));
		goto bail;		
	}
	nbytes = read(fd, buf, sizeof(buf) - 1);
	close(fd);

    if (nbytes < 0) {
	    srand(time(0));
		if(DEBUG_LOG)
			SLOGE("-------------read fd failed\n");
		goto bail;
	}
	buf[nbytes] = '\0';
	bufp = buf;
	if(DEBUG_LOG)
		SLOGE("---------read /sys/class/net/wlan0/address =%s,len=%d",bufp,nbytes);
	while (nbytes > 0) {
		 int matches=0;
		 matches = sscanf(bufp, "%[^:]:%[^:]:%[^:]:%[^:]:%[^:]:%[^:]",value[0],value[1],value[2],value[3],value[4],value[5]);
		 if(matches==6)
		 {
		 	if(DEBUG_LOG)
		 		SLOGE("--------------matches=%d,get wifi mac address,%s:%s:%s%s:%s:%s\n",matches,value[0],value[1],value[2],value[3],value[4],value[5]);		 
		 }

		 // Eat the line.
		 while (nbytes > 0 && *bufp != '\n') {
			 bufp++;
			 nbytes--;
		 }
		 if (nbytes > 0) {
			 bufp++;
			 nbytes--;
		 }
	}
	calc_seed_by_mac(value,seed);

	bail:
	wifi_unload_driver();
	//rmmod(DRIVER_MODULE_NAME);
	for(times=0;times<2;times++)
	{
		if(seed[times]!=0)
		{
			if(DEBUG_LOG)
				SLOGE("-----using seed[%d]=%d---",times,seed[times]);
			srand(seed[times]);
		}
		else if(times == 0)
		{
			if(DEBUG_LOG)
				SLOGE("-----using time as seed----");
			srand(time(0));
		}
		
		for(temp=0;temp<len/2;temp++)
		{
			rand_bit =rand()%36;
			if(rand_bit>=0&&rand_bit<26)//A-Z
			{
				*(result+temp+(len/2*times))=rand_bit+'A';
			}
			else if(rand_bit>=26 && rand_bit <36)//0-9
			{
				*(result+temp+(len/2*times))=(rand_bit-26)+'0';
			}
			if(DEBUG_LOG)
				SLOGE("-------------generate_device_serialno, temp =%d,rand_bit=%d,char=%c",temp,rand_bit,*(result+temp+(len/2*times)));
		}
	}
	result[len]='\0';
	store_serialno(result);
	SLOGE("-------------generate_device_serialno,len =%d,result=%s",len,result);
}
void generate_device_serialno(int len,char*result)
{
        int temp=0,rand_bit=0,times =0;
        int fd,type;
        char buf[32];
        char value[6][2];
        const char *bufp;
        ssize_t nbytes;
        char path[64];
        unsigned int seed[2]={0,0};

        #ifdef DEBUG_RANDOM
                SLOGE("-------DEBUG_RANDOM mode-------");
                goto bail;
        #endif
        //LOUHN 
        if(!get_serialno_cached(result,len))
        {
                SLOGE("----------LOUHN serianno =%s",result);
                return;
        }

        if(check_wlan_mac()<0)//not buffered in data,do it
        {
                fd = open(WIFI_MAC_FILENAME, O_RDONLY);//read form buffered file
                if(fd<0)
                {
                        if(DEBUG_LOG)
                                SLOGE("---------------can not access %s,try to insmod wifi and try again\n",WIFI_MAC_FILENAME);
        
... ...

之前在该平台上遇到一个BUG,serialno会出现unknown的情况,这是因为在生成/data/misc/wifi/serialno文件的时候,serialno的内容被赋为了空,导致系统获取不到字符,这里我加入了一个判断,如果serialno的内容为空,不让程序return掉,继续往下执行再重新生成serialno字符串

diff --git a/system/core/drmservice/drmservice.c b/system/core/drmservice/drmservice.c
index 28b56e111b..5602f89e97 100644
--- a/system/core/drmservice/drmservice.c
+++ b/system/core/drmservice/drmservice.c
@@ -720,7 +720,8 @@ void generate_device_serialno(int len,char*result)
        if(!get_serialno_cached(result,len))
        {
                SLOGE("----------serianno =%s",result);
-               return;
+               if(strlen(result) != 0)
+                       return;
        }
 
        if(check_wlan_mac()<0)//not buffered in data,do it

2.device/rockchip/common/init.rk30board.rc

在init.rk30board.rc目录下,有个set ro.serialno服务,将sys.serialno的值赋给ro.serialno

# set ro.serialno
on property:sys.serialno=*
    setprop ro.serialno ${sys.serialno}

在测试过程中发现rk3288平台会出现serialno相同的情况,这是瑞芯微自生因为随机生成的算法bug导致的,现在我不用通过wifi的MAC去生成serialno, 而是直接用CPU串号去设置固定serialno,修改方法与上面的差不多:

diff --git a/system/core/drmservice/drmservice.c b/system/core/drmservice/drmservice.c
index 5602f89e97..b6ba825bdf 100644
--- a/system/core/drmservice/drmservice.c
+++ b/system/core/drmservice/drmservice.c
@@ -33,7 +33,7 @@
 extern int init_module(void *, unsigned long, const char *);
 extern int delete_module(const char *, unsigned int);
 
-static char sn_buf_auto[32] = {0};
+static char sn_buf_auto[128] = {0};
 static char sn_buf_idb[33] = {0};
 static char hid_buf_idb[33] = {0};
 
@@ -1080,6 +1080,7 @@ void copy_dir(const char *old_path,const char *new_path)
  */
 int main( int argc, char *argv[] )
 {
+       int len = 0, j = 0;
        SLOGE("----------------running drmservice---------------");
     char propbuf_source[PROPERTY_VALUE_MAX];
        char propbuf_dest[PROPERTY_VALUE_MAX];
@@ -1104,7 +1105,34 @@ int main( int argc, char *argv[] )
        }
        else//auto generate serialno
        {
-               generate_device_serialno(10,sn_buf_auto);
+
+               FILE *fp = fopen("/proc/cpuinfo", "r");
+               if(NULL != fp)
+               {
+                
+                   while(!feof(fp))
+                   {
+                       memset(sn_buf_auto,0, sizeof(sn_buf_auto));
+                       fgets(sn_buf_auto,sizeof(sn_buf_auto)-1, fp);
+                       if(strstr(sn_buf_auto,"Serial"))
+                       {
+                               while(sn_buf_auto[len++] != ':');
+                               len++;
+                               while(sn_buf_auto[len])
+                               {
+                                   sn_buf_auto[j++] = sn_buf_auto[len++];
+                               }
+                               sn_buf_auto[j] = '\0';
+                               break; 
+                       }
+                   }
+                   fclose(fp);
+               }
+               else
+               {
+                   printf("failed to open cpuinfo\n");
+                   generate_device_serialno(10,sn_buf_auto);
+               }       
                property_set("sys.serialno", sn_buf_auto[0] ? sn_buf_auto : "");
                         write_serialno2kernel(sn_buf_auto);
                SLOGE("auto generate serialno,serialno = %s",sn_buf_auto);

 

 四、RK3288 Android5.1 设备序列号

RK3288 Android5.1平台的序列号,可以通过设置->关于设备->状态信息→序列号 进行查看,也可以通过adb指令getprop ro.serialno 进行查看。

RK3288 Android5.1固定序列号的方法为通过获取wifi模块的序列号,再把该序列号写入到serialno设备里,具体的源码如下:

system/core/drmservice/drmservice.c

1. main函数下,通过 generate_device_serialno(10,sn_buf_auto);给sn_buf_auto赋值:

2.通过property_set("ro.serialno", sn_buf_auto[0] ? sn_buf_auto : "");给ro.serialno赋值

else//auto generate serialno
       {
               generate_device_serialno(10,sn_buf_auto);
               property_set("ro.serialno", sn_buf_auto[0] ? sn_buf_auto : "");
                write_serialno2kernel(sn_buf_auto);
               SLOGE("auto generate serialno,serialno = %s",sn_buf_auto);
       }

 3.generate_device_serialno的实现是调用get_serialno_cached(result,len)函数

void generate_device_serialno(int len,char*result)
{
        int temp=0,rand_bit=0,times =0;
        int fd,type;
        char buf[32];
        char value[6][2];
        const char *bufp;
        ssize_t nbytes;
        char path[64];
        unsigned int seed[2]={0,0};
 
        #ifdef DEBUG_RANDOM
                SLOGE("-------DEBUG_RANDOM mode-------");
                goto bail;
        #endif
 
        if(!get_serialno_cached(result,len))
        {
                SLOGE("----------serianno =%s",result);
                return;
        }
... ...

 

4.get_serialno_cached函数具体内容就是读取wifi模块的序列号,并返回result 

int get_serialno_cached(char * result,int len)
{
        int fd,readlen;
        char buf[32];
        fd = open(DEVICE_SERIALNO, O_RDONLY);//louhn :DEVICE_SERIALNO = /data/misc/wifi/serialno
        if (fd < 0)
        {
                        if(DEBUG_LOG)
                        SLOGE("--------------------------[%s] has not been created", DEVICE_SERIALNO);
                return -1;
        }
        readlen=read(fd, buf, sizeof(buf) - 1);
        /*
        if(readlen != len)
        {
                if(DEBUG_LOG)
                        SLOGE("---get_serialno_cached,wanted len =%d,but cached len =%d",len,readlen);
                return -1;
        }
        */
        memcpy(result,buf,readlen);
        buf[readlen]='\0';
        close(fd);
        return 0;
}