在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,同样放在执行队列的最后,确没有成功。log显示读取文件失败。
先是怀疑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);
}