在and4.4上之前在init进程中读取amt/sn.txt中的内容,设置到"ro.serialno"的系统属性中。而Settings会去读取这个属性的值,从而将手机的序列码显示出来。
if (!is_charger) { action_for_each_trigger("early-fs", action_add_queue_tail); action_for_each_trigger("fs", action_add_queue_tail); action_for_each_trigger("post-fs", action_add_queue_tail); action_for_each_trigger("post-fs-data", action_add_queue_tail); } /* Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random * wasn't ready immediately after wait_for_coldboot_done */ queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng"); queue_builtin_action(property_service_init_action, "property_service_init"); queue_builtin_action(signal_init_action, "signal_init"); queue_builtin_action(check_startup_action, "check_startup"); queue_builtin_action(set_usb_serial_action, "set_usb_serial_action");
set_usb_serial_action函数就是读取sn.txt的内容,如果没有这个文件再从/amt/nvram_amt_data.bin读取,这里就不再详细展开这个函数。
直接看代码吧:
static int set_usb_serial_action(int nargs,char **args) { FILE *fp; char serial_no[LINE_SIZE] = {0}; int len = 0; bool isSNExist = true; fp = fopen(SN_FILE, "r"); if (fp == NULL) { isSNExist = false; ERROR("file %s is not exist in AMT\n", SN_FILE); fp = fopen(NVRAM_AMT_DATA_FILE, "r"); if (fp == NULL) { property_set("ro.serialno", ""); ERROR("both %s and %s is not exist in AMT\n", SN_FILE, NVRAM_AMT_DATA_FILE); goto fail_exit; } int result = fseek(fp, 0x560, SEEK_SET); if (result) { property_set("ro.serialno",""); ERROR("seek file %s error", NVRAM_AMT_DATA_FILE); goto fail_exit; } } if (fgets(serial_no, LINE_SIZE, fp) == NULL) { ERROR("read file error"); property_set("ro.serialno",""); goto fail_exit; } for (len = 0; len < LINE_SIZE; len++) { if(serial_no[len] == 0) break; } if (len == 0) { property_set("ro.serialno","0123456789ABCDEF"); goto fail_exit; } property_set("ro.serialno", serial_no); fclose(fp); if (!isSNExist) { fp = fopen(SN_FILE, "w"); if (fp) { fwrite(serial_no, sizeof(char), len, fp); fclose(fp); chown(SN_FILE, AID_ROOT, AID_RADIO); chmod(SN_FILE, S_IRUSR | S_IWUSR); } } return 0; fail_exit: if (fp) fclose(fp); return -1; }
先是怀疑5.1上开启了selinux,于是在init.te中加入了对/amt目录的读取权限,但还是不行,将selinux的CR回退结果还是一样。于是就排除了selinux的问题。
排序selinux的问题后,基本上确定是amt分区还没有加载的原因。
于是先去搜4.1的init.rc,将amt分区挂载是在fs触发器中,在4.4的init是将fs这个触发器单独放在执行列表中,而我们的函数放在其后面,所以是没有问题的。
fs触发器的内容如下,其中就有挂载amt分区
on fs # mount partitions mount_all /fstab.leadcoreinnopower # enable swap swapon_all /fstab.leadcoreinnopower write /proc/sys/vm/page-cluster 0 # If no amt file, to prevent the failure of mount_all mount ext4 /dev/block/platform/comip-mmc.1/by-name/amt /amt wait rw copy /amt/vbatt /proc/driver/comip_battery setprop ro.crypto.fuse_sdcard true
然而5.1上是将fs这个触发器放在:
on late-init trigger early-fs trigger fs trigger post-fs trigger post-fs-data因此,在代码里放进执行队列的只是late-init,执行到late-init后再把fs等再加入执行队列。而这一步骤是在解析执行队列的时候,所以我们在之前加入队列,是肯定在fs之前了,也就是在amt分区还没有挂载的时候就去读取其中的文件,所以就出错了。
if (is_charger) { action_for_each_trigger("charger", action_add_queue_tail); } else { action_for_each_trigger("late-init", action_add_queue_tail); }解决的方法,是在解析到fs这个触发器的时候,再把我们这个函数加入执行队列中,这样就把这个问题解决了:
void execute_one_command(void) { int ret, i; char cmd_str[256] = ""; if (!cur_action || !cur_command || is_last_command(cur_action, cur_command)) { cur_action = action_remove_queue_head(); cur_command = NULL; if (!cur_action) return; INFO("processing action %p (%s)\n", cur_action, cur_action->name); if (!strcmp(cur_action->name, "fs")) { queue_builtin_action(set_usb_serial_action, "set_usb_serial_action");// 解析到fs后,再把我们的函数加入到执行队列尾 } cur_command = get_first_command(cur_action); } else { cur_command = get_next_command(cur_action, cur_command); }