Android 分区挂载
16lz
2021-01-23
Android启动之后,系统的分区工作已经完成,但是分区是在哪来进行的?
一个大的系统启动不可能每个分区都要去手动挂载,添加,肯定有一个自动加载的工作,Android 本身也是一个Linux系统,我们先从Linux的分区开始了解。
Linux系统分区
linux 开机时会 自动加载分区,只不过要先配置好分区文件fstab (/etc/fstab),如下: # /etc/fstab /dev/hda9 swap swap defaults 0 0 /dev/hda1 / ext2 defaults 1 1 /dev/hda5 /home ext2 defaults 1 1 /dev/hda6 /usr ext2 defaults 1 1 /dev/hda7 /usr/local ext2 defaults 1 1 /dev/hda8 /var ext2 defaults 1 1 /dev/hdb /cdrom iso9660 noauto,user 0 0 none /proc proc defaults 0 0 none /dev/pts devpts gid=5,mode=620 0 0
fstab文件的作用
文件/etc/fstab存放的是系统中的文件系统信息。当正确的设置了该文件,则可以通过"mount /directoryname"命令来加载
一个文件系统,每种文件系统都对应一个独立的行,每行中的字段都有空格或tab键分开。同时fsck、 mount、umount的等命令都
利用该程序。
fstab文件格式
下面是/etc/fatab文件的一个示例行:
fs_spec fs_file fs_type fs_options fs_dump fs_pass
/dev/hda1 / ext2 defaults 1 1
fs_spec - 该字段定义希望加载的文件系统所在的设备或远程文件系统,对于一般的本地块设备情况来说:IDE设备一般描述为
/dev/hdaXN,X是IDE设备通道 (a, b, or c),N代表分区号;SCSI设备一描述为/dev/sdaXN。对于NFS情况,格式一般为:
例 如:`knuth.aeb.nl:/'。对于procfs,使用`proc'来定义。
fs_file - 该字段描述希望的文件系统加载的目录点,对于swap设备,该字段为none;对于加载目录名包含空格的情况,用40来
表示空格。
fs_type - 定义了该设备上的文件系统,一般常见的文件类型为ext2 (linux设备的常用文件类型)、vfat(Windows系统的fat32格
式)、NTFS、iso9600等。
fs_options - 指定加载该设备的文件系统是需要使用的特定参数选项,多个参数是由逗号分隔开来。对于大多数系统使用"defaults"
就可以满足需要。其他常见的选项包括:
选项含义
ro 以只读模式加载该文件系统
sync 不对该设备的写操作进行缓冲处理,这可以防止在非正常关机时情况下破坏文件系统,但是却降低了计算机速度
user 允许普通用户加载该文件系统
quota 强制在该文件系统上进行磁盘定额限制
noauto 不再使用mount -a命令(例如系统启动时)加载该文件系统
fs_dump - 该选项被"dump"命令使用来检查一个文件系统应该以多快频率进行转储,若不需要转储就设置该字段为0
fs_pass - 该字段被fsck命令用来决定在启动时需要被扫描的文件系统的顺序,根文件系统"/"对应该字段的值应该为1,其他文件系统应该为2。若该文件系统无需在启动时扫描则设置该字段为0
Android系统分区文件
android系统也有自己的系统分区文件fstab.${ro.hardware} ,一般为fstab.muji , fstab.monet, ..... 例如:fstab.muji文件# Android fstab file.# # The filesystem that contains the filesystem checker binary (typically /system) cannot# specify MF_CHECK, and must come before any filesystems that do specify MF_CHECK/dev/block/platform/mstar_mci.0/by-name/system /system ext4 ro wait/dev/block/platform/mstar_mci.0/by-name/cache /cache ext4 noatime,nosuid,nodev wait,block_validity,nodiscard,data=ordered,journal_checksum/dev/block/platform/mstar_mci.0/by-name/userdata /data ext4 noatime,nosuid,nodev wait,block_validity,nodiscard,data=ordered,journal_checksum/dev/block/platform/mstar_mci.0/by-name/tvservice /tvservice ext4 ro wait/dev/block/platform/mstar_mci.0/by-name/tvconfig /tvconfig ext4 noatime,nosuid,nodev wait,block_validity,nodiscard,data=ordered,journal_checksum/dev/block/platform/mstar_mci.0/by-name/tvdatabase /tvdatabase ext4 noatime,nosuid,nodev wait,block_validity,nodiscard,data=ordered,journal_checksum/dev/block/platform/mstar_mci.0/by-name/tvcustomer /tvcustomer ext4 noatime,nosuid,nodev wait,block_validity,nodiscard,data=ordered,journal_checksum/dev/block/platform/mstar_mci.0/by-name/usersdcard /usersdcard vfat noatime,nosuid,nodev wait,block_validity,nodiscard,data=ordered,journal_checksum/dev/block/platform/mstar_mci.0/by-name/factory /factory ext4 noatime,nosuid,nodev wait,block_validity,nodiscard,data=ordered,journal_checksum/dev/block/mmcblk0boot0 /boot1 emmc defaults defaults/dev/block/mmcblk0boot1 /boot2 emmc defaults defaults/dev/block/platform/mstar_mci.0/by-name/MBOOT /MBOOT emmc defaults defaults/dev/block/platform/mstar_mci.0/by-name/MPOOL /MPOOL emmc defaults defaults/dev/block/platform/mstar_mci.0/by-name/misc /misc emmc defaults defaults/dev/block/platform/mstar_mci.0/by-name/recovery /recovery emmc defaults defaults/dev/block/platform/mstar_mci.0/by-name/boot /boot emmc defaults defaults/dev/block/platform/mstar_mci.0/by-name/tee /tee emmc defaults defaults/dev/block/platform/mstar_mci.0/by-name/RTPM /RTPM emmc defaults defaults/dev/block/platform/mstar_mci.0/by-name/dtb /dtb emmc defaults defaults
这里描述了系统所有分区位置,挂载点,类型,一些挂载参数 分区启动方式
从源码看,目前发现有两处地方有进行分区的动作:1. init脚本 ; 2. vold服务程序 3. fs_mgrinit脚本
on fs mkdir /tvservice mkdir /tvconfig mkdir /tvdatabase mkdir /tvcustomer mount_all /fstab.monet
mount_all 命令在system\core\init\keywords.h中注册 KEYWORD(mount_all, COMMAND, 1, do_mount_all)
接着会调用init进程的do_mount_all (builtins.c文件) /* * This function might request a reboot, in which case it will * not return. */int do_mount_all(int nargs, char **args){ pid_t pid; int ret = -1; int child_ret = -1; int status; const char *prop; struct fstab *fstab; if (nargs != 2) { return -1; } /* * Call fs_mgr_mount_all() to mount all filesystems. We fork(2) and * 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) { /* 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, errno=%d\n", wp_ret, 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 */ fstab = fs_mgr_read_fstab(args[1]); 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; } ...... return ret;}
fs_mgr_read_fstab完整fstab.muji 的解析,fs_mgr_mount_all完成所有目录的挂载 vold服务
该服务主程序源码位于system\vold\main.cpp,通过函数process_config 调用fs_mgr_read_fstab完成文件的解析,注册的CommandListener在接收到mountall指令之后 完成所有分区注册:int CommandListener::StorageCmd::runCommand(SocketClient *cli, int argc, char **argv) { /* Guarantied to be initialized by vold's main() before the CommandListener is active */ extern struct fstab *fstab; dumpArgs(argc, argv, -1); if (argc < 2) { cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false); return 0; } if (!strcmp(argv[1], "mountall")) { if (argc != 2) { cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: mountall", false); return 0; } fs_mgr_mount_all(fstab); cli->sendMsg(ResponseCode::CommandOkay, "Mountall ran successfully", false); return 0; } if (!strcmp(argv[1], "users")) { DIR *dir; struct dirent *de; if (argc < 3) { cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument: user ", false); return 0; } if (!(dir = opendir("/proc"))) { cli->sendMsg(ResponseCode::OperationFailed, "Failed to open /proc", true); return 0; } while ((de = readdir(dir))) { int pid = Process::getPid(de->d_name); if (pid < 0) { continue; } char processName[255]; Process::getProcessName(pid, processName, sizeof(processName)); if (Process::checkFileDescriptorSymLinks(pid, argv[2]) || Process::checkFileMaps(pid, argv[2]) || Process::checkSymLink(pid, argv[2], "cwd") || Process::checkSymLink(pid, argv[2], "root") || Process::checkSymLink(pid, argv[2], "exe")) { char msg[1024]; snprintf(msg, sizeof(msg), "%d %s", pid, processName); cli->sendMsg(ResponseCode::StorageUsersListResult, msg, false); } } closedir(dir); cli->sendMsg(ResponseCode::CommandOkay, "Storage user list complete", false); } else { cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown storage cmd", false); } return 0;}
我们可以看到在fs_mgr_mount_all(fstab);之后所有客户端。 fs_mgr 进程
该服务源码位于system\core\fs_mgr\fs_mgr_main.c,该模块是解析分区文件,并完成挂载任务的最终工作者。更多相关文章
- Android的属性Property系统
- Android 图形系统之图形缓冲区分配
- Android窗口系统第三篇---WindowManagerService中窗口的组织方式
- Android系统多媒体框架添加对.wma格式的支持
- [Hi3751V811][Android8.0]系统按键的转换 - android键值的映射
- 理解WebKit和Chromium: 调试Android系统上的Chromium
- android的图形系统