Android 分区挂载

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.
#<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脚本

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 <mountpoint>", 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,该模块是解析分区文件,并完成挂载任务的最终工作者。



  • 5
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值