搜索
 找回密码
 立即注册

简单一步 , 微信登陆

Android 分区挂载

作者:果果 | 时间:2016-9-30 17:34:16 | 阅读:7795| 只看该作者

Android 分区挂载
Android启动之后,系统的分区工作已经完成,但是分区是在哪来进行的?
一个大的系统启动不可能每个分区都要去手动挂载,添加,肯定有一个自动加载的工作,Android 本身也是一个Linux系统,我们先从Linux的分区开始了解。

Linux系统分区linux 开机时会自动加载分区,只不过要先配置好分区文件fstab (/etc/fstab),如下:
[plain] view plaincopy
  • # /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_opti** 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_opti** - 指定加载该设备的文件系统是需要使用的特定参数选项,多个参数是由逗号分隔开来。对于大多数系统使用"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文件
[plain] view plaincopy
  • # Android fstab file.  
  • #<src>                                                  <mnt_point>         <type>    <mnt_flags>                                          <fs_mgr_flags>  
  • # 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_mgr

init脚本[plain] view plaincopy
  • on fs   
  •     mkdir /tvservice   
  •     mkdir /tvconfig   
  •     mkdir /tvdatabase   
  •     mkdir /tvcustomer   
  •     mount_all /fstab.monet   

mount_all 命令在system\core\init\keywords.h中注册

[plain] view plaincopy
  • KEYWORD(mount_all,   COMMAND, 1, do_mount_all)  

接着会调用init进程的do_mount_all (builtins.c文件)
[cpp] view plaincopy
  • /*
  • * 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;  
  •     c**t 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指令之后
完成所有分区注册:
[cpp] view plaincopy
  • 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(Resp**eCode::CommandSyntaxError, "Missing Argument", false);  
  •         return 0;  
  •     }  
  •   
  •     if (!strcmp(argv[1], "mountall")) {  
  •         if (argc != 2) {  
  •             cli->sendMsg(Resp**eCode::CommandSyntaxError, "Usage: mountall", false);  
  •             return 0;  
  •         }  
  •         fs_mgr_mount_all(fstab);  
  •         cli->sendMsg(Resp**eCode::CommandOkay, "Mountall ran successfully", false);  
  •         return 0;  
  •     }  
  •     if (!strcmp(argv[1], "users")) {  
  •         DIR *dir;  
  •         struct dirent *de;  
  •   
  •         if (argc < 3) {  
  •             cli->sendMsg(Resp**eCode::CommandSyntaxError, "Missing Argument: user <mountpoint>", false);  
  •             return 0;  
  •         }  
  •         if (!(dir = opendir("/proc"))) {  
  •             cli->sendMsg(Resp**eCode::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(Resp**eCode::StorageUsersListResult, msg, false);  
  •             }  
  •         }  
  •         closedir(dir);  
  •         cli->sendMsg(Resp**eCode::CommandOkay, "Storage user list complete", false);  
  •     } else {  
  •         cli->sendMsg(Resp**eCode::CommandSyntaxError, "Unknown storage cmd", false);  
  •     }  
  •     return 0;  
  • }  

我们可以看到在fs_mgr_mount_all(fstab);之后所有客户端。


fs_mgr 进程该服务源码位于system\core\fs_mgr\fs_mgr_main.c,该模块是解析分区文件,并完成挂载任务的最终工作者




收藏
收藏0
分享
分享
点赞
点赞9
反对
反对0
回复

使用道具 举报

大神点评1

沙发#
Jack.Lin 发表于:2016-10-9 09:45:20
不错,收藏起来。
该会员没有填写今日想说内容.
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册
手机版