android文件系统挂载分析---正常开机挂载
Posted cuixiaolei的技术博客
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了android文件系统挂载分析---正常开机挂载相关的知识,希望对你有一定的参考价值。
"android"系列分为三部分:
1.正常开机挂载
2.encryption
3.dm-verity
我们知道android有很多分区,如"system","userdata","cache",他们是何时挂载的?如何挂载的?这个系列的文章进行分析。这里介绍第一部分,android手机正常开机各分区的挂载。这里我们以mtk平台进行分析,高通与mtk差别不是很大。
我们知道kernel起来以后执行的第一个文件是init进程,init进程会根据init.rc的规则启动进程或者服务。init.rc通过"import /init.${ro.hardware}.rc"语句导入平台的规则。
device/mediatek/mt6797/init.mt6797.rc on fs write /proc/bootprof "INIT:Mount_START" mount_all /fstab.mt6797 chown system system /mobile_info chmod 0771 /mobile_info exec /system/bin/tune2fs -O has_journal -u 10010 -r 4096 /dev/block/platform/mtk-msdc.0/11230000.msdc0/by-name/userdata write /proc/bootprof "INIT:Mount_END"
mount_all是一条命令,/fstab.mt6797是传入的参数
system/core/init/keywords.h ..... KEYWORD(mount_all, COMMAND, 1, do_mount_all) .....
从上面我们可以看出,mount_all命令对应的是do_mount_all函数,/fstab.mt6797是do_mount_all函数的传入参数
system/core/init/builtins.cpp int do_mount_all(int nargs, char **args) { pid_t pid; int ret = -1; int child_ret = -1; int status; struct fstab *fstab; if (nargs != 2) { return -1; } /* * Call fs_mgr_mount_all() to mount all filesystems. We fork(2) and //使用fs_mgr_mount_all()函数去挂载所有的文件系统,我们使用fork()函数分配一个新的进程,在子进程中做挂载的事情,这样即使挂载出现问题,也能保护init主进程。 * do the call in the child to provide protection to the main init * process if anything goes wrong (crash or memory leak), and wait for * the child to finish in the parent. */ pid = fork(); if (pid > 0) { //父进程,等待子进程(pid=0)返回 /* Parent. Wait for the child to return */ int wp_ret = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0)); if (wp_ret < 0) { /* Unexpected error code. We will continue anyway. */ NOTICE("waitpid failed rc=%d: %s\n", wp_ret, strerror(errno)); } if (WIFEXITED(status)) { ret = WEXITSTATUS(status); } else { ret = -1; } } else if (pid == 0) { //子进程 /* child, call fs_mgr_mount_all() */ klog_set_level(6); /* So we can see what fs_mgr_mount_all() does */ //修改kernel log的等级,让我们可以看到fs_mgr_mount_all函数的log fstab = fs_mgr_read_fstab(args[1]); //args[1]是传入的参数/fstab.mt6797,是一个文件。 加载分区挂载文件的内容到fstab结构体中。 child_ret = fs_mgr_mount_all(fstab); //挂载分区******************* fs_mgr_free_fstab(fstab); if (child_ret == -1) { ERROR("fs_mgr_mount_all returned an error\n"); } _exit(child_ret); } else { /* fork failed, return an error */ return -1; } if (ret == FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION) { property_set("vold.decrypt", "trigger_encryption"); } else if (ret == FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED) { property_set("ro.crypto.state", "encrypted"); property_set("ro.crypto.type", "block"); property_set("vold.decrypt", "trigger_default_encryption"); } else if (ret == FS_MGR_MNTALL_DEV_NOT_ENCRYPTED) { property_set("ro.crypto.state", "unencrypted"); /* If fs_mgr determined this is an unencrypted device, then trigger * that action. */ action_for_each_trigger("nonencrypted", action_add_queue_tail); } else if (ret == FS_MGR_MNTALL_DEV_NEEDS_RECOVERY) { /* Setup a wipe via recovery, and reboot into recovery */ ERROR("fs_mgr_mount_all suggested recovery, so wiping data via recovery.\n"); ret = wipe_data_via_recovery(); /* If reboot worked, there is no return. */ } else if (ret == FS_MGR_MNTALL_DEV_DEFAULT_FILE_ENCRYPTED) { if (e4crypt_install_keyring()) { return -1; } property_set("ro.crypto.state", "encrypted"); property_set("ro.crypto.type", "file"); // Although encrypted, we have device key, so we do not need to // do anything different from the nonencrypted case. action_for_each_trigger("nonencrypted", action_add_queue_tail); } else if (ret == FS_MGR_MNTALL_DEV_NON_DEFAULT_FILE_ENCRYPTED) { if (e4crypt_install_keyring()) { return -1; } property_set("ro.crypto.state", "encrypted"); property_set("ro.crypto.type", "file"); property_set("vold.decrypt", "trigger_restart_min_framework"); } else if (ret > 0) { ERROR("fs_mgr_mount_all returned unexpected error %d\n", ret); } /* else ... < 0: error */ return ret; }
fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同,两个进程也可以做不同的事。返回值小于0为error,返回值等于0为子进程,返回值大于0为父进程。
args[1]是传入的参数/fstab.mt6797,是一个文件,生成的位置在/out/target/product/xxx/root/fstab.mt6797,生成这个文件的源文件位于vendor/mediatek/proprietary/hardware/fstab/mt6797/,根据编译规则确定fstab.mt6797文件的内容。
在do_mount_all()函数中,比较重要的两个函数如下,我们分析一下这两个函数
stab = fs_mgr_read_fstab(args[1]);
child_ret = fs_mgr_mount_all(fstab);
首先我们看下fstab结构体和fstab.mt6797文件,fstab结构提要存储fstab.mt6797文件中的挂载信息,
struct fstab { int num_entries; struct fstab_rec *recs; char *fstab_filename; }; struct fstab_rec { char *blk_device; char *mount_point; char *fs_type; unsigned long flags; char *fs_options; int fs_mgr_flags; char *key_loc; char *verity_loc; long long length; char *label; int partnum; int swap_prio; unsigned int zram_size; };
out/target/product/xxx/root/fstab.mt6797 # 1 "vendor/mediatek/proprietary/hardware/fstab/mt6797/fstab.in" # 1 "<built-in>" # 1 "<命令行>" # 1 "vendor/mediatek/proprietary/hardware/fstab/mt6797/fstab.in" # 20 "vendor/mediatek/proprietary/hardware/fstab/mt6797/fstab.in" /dev/block/platform/mtk-msdc.0/11230000.msdc0/by-name/system /system ext4 ro wait,verify /dev/block/platform/mtk-msdc.0/11230000.msdc0/by-name/userdata /data ext4 noatime,nosuid,nodev,noauto_da_alloc,discard wait,check,resize,forceencrypt=/dev/block/platform/mtk-msdc.0/11230000.msdc0/by-name/metadata, /dev/block/platform/mtk-msdc.0/11230000.msdc0/by-name/cache /cache ext4 noatime,nosuid,nodev,noauto_da_alloc,discard wait,check /dev/block/platform/mtk-msdc.0/11230000.msdc0/by-name/protect1 /protect_f ext4 noatime,nosuid,nodev,noauto_da_alloc,commit=1,nodelalloc wait,check,formattable /dev/block/platform/mtk-msdc.0/11230000.msdc0/by-name/protect2 /protect_s ext4 noatime,nosuid,nodev,noauto_da_alloc,commit=1,nodelalloc wait,check,formattable /dev/block/platform/mtk-msdc.0/11230000.msdc0/by-name/nvdata /nvdata ext4 noatime,nosuid,nodev,noauto_da_alloc,discard wait,check,formattable /dev/block/platform/mtk-msdc.0/11230000.msdc0/by-name/nvcfg /nvcfg ext4 noatime,nosuid,nodev,noauto_da_alloc,commit=1,nodelalloc wait,check,formattable /dev/block/platform/mtk-msdc.0/11230000.msdc0/by-name/mobile_info /mobile_info ext4 noatime,nosuid,nodev,noauto_da_alloc,discard wait,check # 39 "vendor/mediatek/proprietary/hardware/fstab/mt6797/fstab.in" /devices/mtk-msdc.0/11230000.msdc0* auto vfat defaults voldmanaged=sdcard0:auto /devices/mtk-msdc.0/11240000.msdc1* auto auto defaults voldmanaged=sdcard1:auto,encryptable=userdata /devices/soc/11270000.usb3_xhci* auto vfat defaults voldmanaged=usbotg:auto /dev/block/platform/mtk-msdc.0/11230000.msdc0/by-name/frp /persistent emmc defaults defaults /dev/block/platform/mtk-msdc.0/11230000.msdc0/by-name/nvram /nvram emmc defaults defaults /dev/block/platform/mtk-msdc.0/11230000.msdc0/by-name/proinfo /proinfo emmc defaults defaults /dev/block/platform/mtk-msdc.0/11230000.msdc0/by-name/lk /bootloader emmc defaults defaults /dev/block/platform/mtk-msdc.0/11230000.msdc0/by-name/lk2 /bootloader2 emmc defaults defaults /dev/block/platform/mtk-msdc.0/11230000.msdc0/by-name/para /misc emmc defaults defaults /dev/block/platform/mtk-msdc.0/11230000.msdc0/by-name/boot /boot emmc defaults defaults /dev/block/platform/mtk-msdc.0/11230000.msdc0/by-name/recovery /recovery emmc defaults defaults /dev/block/platform/mtk-msdc.0/11230000.msdc0/by-name/logo /logo emmc defaults defaults /dev/block/platform/mtk-msdc.0/11230000.msdc0/by-name/expdb /expdb emmc defaults defaults /dev/block/platform/mtk-msdc.0/11230000.msdc0/by-name/seccfg /seccfg emmc defaults defaults /dev/block/platform/mtk-msdc.0/11230000.msdc0/by-name/tee1 /tee1 emmc defaults defaults /dev/block/platform/mtk-msdc.0/11230000.msdc0/by-name/tee2 /tee2 emmc defaults defaults /dev/block/platform/mtk-msdc.0/11230000.msdc0/by-name/scp1 /scp1 emmc defaults defaults /dev/block/platform/mtk-msdc.0/11230000.msdc0/by-name/scp2 /scp2 emmc defaults defaults /dev/block/platform/mtk-msdc.0/11230000.msdc0/by-name/md1img /md1img emmc defaults defaults /dev/block/platform/mtk-msdc.0/11230000.msdc0/by-name/md1dsp /md1dsp emmc defaults defaults /dev/block/platform/mtk-msdc.0/11230000.msdc0/by-name/md1arm7 /md1arm7 emmc defaults defaults /dev/block/platform/mtk-msdc.0/11230000.msdc0/by-name/md3img /md3img emmc defaults defaults
我们先分析fstab结构体存放的挂载信息,通过fs_mgr_read_fstab实现
system/core/fs_mgr_fstab.c struct fstab *fs_mgr_read_fstab(const char *fstab_path) //从上面可以知道fstab_path为/fstab.mt6797 { FILE *fstab_file; int cnt, entries; ssize_t len; size_t alloc_len = 0; char *line = NULL; const char *delim = " \t"; char *save_ptr, *p; struct fstab *fstab = NULL; struct fs_mgr_flag_values flag_vals; #define FS_OPTIONS_LEN 1024 char tmp_fs_options[FS_OPTIONS_LEN]; fstab_file = fopen(fstab_path, "r"); //打开文件 if (!fstab_file) { ERROR("Cannot open file %s\n", fstab_path); return 0; } entries = 0; while ((len = getline(&line, &alloc_len, fstab_file)) != -1) { //一行一行的读取文件内容 /* if the last character is a newline, shorten the string by 1 byte */ if (line[len - 1] == ‘\n‘) { line[len - 1] = ‘\0‘; } /* Skip any leading whitespace */ p = line; while (isspace(*p)) { p++; } /* ignore comments or empty lines */ if (*p == ‘#‘ || *p == ‘\0‘) continue; entries++; } if (!entries) { ERROR("No entries found in fstab\n"); goto err; } /* Allocate and init the fstab structure */ fstab = calloc(1, sizeof(struct fstab)); fstab->num_entries = entries; fstab->fstab_filename = strdup(fstab_path); fstab->recs = calloc(fstab->num_entries, sizeof(struct fstab_rec)); fseek(fstab_file, 0, SEEK_SET); cnt = 0; while ((len = getline(&line, &alloc_len, fstab_file)) != -1) { /* if the last character is a newline, shorten the string by 1 byte */ if (line[len - 1] == ‘\n‘) { line[len - 1] = ‘\0‘; } /* Skip any leading whitespace */ p = line; while (isspace(*p)) { p++; } /* ignore comments or empty lines */ if (*p == ‘#‘ || *p == ‘\0‘) continue; /* If a non-comment entry is greater than the size we allocated, give an * error and quit. This can happen in the unlikely case the file changes * between the two reads. */ if (cnt >= entries) { ERROR("Tried to process more entries than counted\n"); break; } if (!(p = strtok_r(line, delim, &save_ptr))) { ERROR("Error parsing mount source\n"); goto err; } fstab->recs[cnt].blk_device = strdup(p); if (!(p = strtok_r(NULL, delim, &save_ptr))) { ERROR("Error parsing mount_point\n"); goto err; } fstab->recs[cnt].mount_point = strdup(p); if (!(p = strtok_r(NULL, delim, &save_ptr))) { ERROR("Error parsing fs_type\n"); goto err; } fstab->recs[cnt].fs_type = strdup(p); if (!(p = strtok_r(NULL, delim, &save_ptr))) { ERROR("Error parsing mount_flags\n"); goto err; } tmp_fs_options[0] = ‘\0‘; fstab->recs[cnt].flags = parse_flags(p, mount_flags, NULL, tmp_fs_options, FS_OPTIONS_LEN); /* fs_options are optional */ if (tmp_fs_options[0]) { fstab->recs[cnt].fs_options = strdup(tmp_fs_options); } else { fstab->recs[cnt].fs_options = NULL; } if (!(p = strtok_r(NULL, delim, &save_ptr))) { ERROR("Error parsing fs_mgr_options\n"); goto err; } fstab->recs[cnt].fs_mgr_flags = parse_flags(p, fs_mgr_flags, &flag_vals, NULL, 0); fstab->recs[cnt].key_loc = flag_vals.key_loc; fstab->recs[cnt].verity_loc = flag_vals.verity_loc; fstab->recs[cnt].length = flag_vals.part_length; fstab->recs[cnt].label = flag_vals.label; fstab->recs[cnt].partnum = flag_vals.partnum; fstab->recs[cnt].swap_prio = flag_vals.swap_prio; fstab->recs[cnt].zram_size = flag_vals.zram_size; cnt++; } fclose(fstab_file); free(line); return fstab; err: fclose(fstab_file); free(line); if (fstab) fs_mgr_free_fstab(fstab); return NULL; }
以上是关于android文件系统挂载分析---正常开机挂载的主要内容,如果未能解决你的问题,请参考以下文章