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
由上可知道方法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:
4.在frameworks/base/core/java/android/os/Build.java中定义了一个Build类
5.系统设置->关于平板电脑(手机)->状态信息在 packages/apps/Settings/src/com/android/settings/deviceinfo/Staus.java进 行设置
import android.os.Build; ==>包含了frameworks/base/core/java/android/os/Build.java中定义的一个Build类
6.至此,整个流程结束~
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的方法;
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.至此,整个流程结束~