Android 9.0 Vold挂载流程解析(上)

前言

我们分2篇文章来介绍Android 9.0中存储卡的挂载流程,本篇文章先介绍总体的挂载模块、Vold进程的入口main函数的详细分析,有了这些基础知识,下一篇中我们再详细介绍收到驱动层消息是怎么挂载和卸载存储卡的,还有framework层如何与vold进程通讯交流。Android 9.0 Vold挂载流程解析(下)

Android挂载模块整体框架

存储卡挂载模块由驱动层、vold进程、framework层、App层这几个模块注册,vold进程通过Socket方式监听驱动层存储卡热插拔事件(Add、Change 、Remove),创建相应的磁盘管理类,管理磁盘的生命周期状态,提供挂载、卸载等功能,并把相应磁盘信息状态通过Binder的方式回调给Framework层,方便App层获取磁盘信息和状态。以下是其整体的模块框架图:

从图中我们知道vold有三个核心的类,NetlinkManager、VolumeManager、VoldNativeService,这三个类在启动vold进程时就会调用其start方法启动,NetlinkManager里创建了Socket连接并交给NetlinkHandler处理通讯,由NetlinkHandler监听驱动层发送的uevent事件,并转发给VolumeManager处理,VolumeManager接受到相应的事件,会创建存储管理的类获取存储卡的信息和状态的并通过VoldNativeService回调给Framework层StorageManagerService处理,StroageManagerService也可以通过binder机制调用VoldNativeSerivice的方法,设置userId,shutdown等,好让vold进程进行相应的处理。StorageManagerService也提供了存储卡操作相关的方法给APP调用,App通过获取StorageManager类间接调用StorageManagerService中的方法。

Vold进程main函数详细分析

我们从Vold进程的main.cpp中入手开始分析

vold进程main.cpp路径:system/vold/main.cpp

c 复制代码
int main(int argc, char** argv) {
   atrace_set_tracing_enabled(false);
   //设置日志等级
   setenv("ANDROID_LOG_TAGS", "*:v", 1);
   android::base::InitLogging(argv, android::base::LogdLogger(android::base::SYSTEM));

   LOG(INFO) << "Vold 3.0 (the awakening) firing up";

   ATRACE_BEGIN("main");

  //打印支持的底层文件系统
   LOG(VERBOSE) << "Detected support for:"
           << (android::vold::IsFilesystemSupported("ext4") ? " ext4" : "")
           << (android::vold::IsFilesystemSupported("f2fs") ? " f2fs" : "")
           << (android::vold::IsFilesystemSupported("vfat") ? " vfat" : "")
           // Mediatek Android Patch Begin
           << (android::vold::IsFilesystemSupported("ntfs") ? " ntfs" : "")
           << (android::vold::IsFilesystemSupported("cifs") ? " cifs" : "");
           // Mediatek Android Patch End

   VolumeManager *vm;
   NetlinkManager *nm;
   //解析参数
   parse_args(argc, argv);

   sehandle = selinux_android_file_context_handle();
   if (sehandle) {
       selinux_android_set_sehandle(sehandle);
   }
//创建/dev/block/vold目录,挂载存储卡了其下有对应的节点信息
   mkdir("/dev/block/vold", 0755);

   /* For when cryptfs checks and mounts an encrypted filesystem */
   klog_set_level(6);

   /* Create our singleton managers */
   //单例模式获取VolumeManager对象
   if (!(vm = VolumeManager::Instance())) {
       LOG(ERROR) << "Unable to create VolumeManager";
       exit(1);
   }
//单例模式获取NetlinkManager对象
   if (!(nm = NetlinkManager::Instance())) {
       LOG(ERROR) << "Unable to create NetlinkManager";
       exit(1);
   }
//设置是否打开VolumeManager中的日志,默认false
   if (android::base::GetBoolProperty("vold.debug", false)) {
       vm->setDebug(true);
   }
//调用其start方法,稍后分析 1
   if (vm->start()) {
       PLOG(ERROR) << "Unable to start VolumeManager";
       exit(1);
   }

   bool has_adoptable;
   bool has_quota;
   bool has_reserved;
//解析fstab文件,该文件描述系统中各种文件系统的信息;我以MTK9669为例分析其fsab文件路径在vendor/etc/fstab.m7642
//稍后详细分析该方法 2
   if (process_config(vm, &has_adoptable, &has_quota, &has_reserved)) {
       PLOG(ERROR) << "Error reading configuration... continuing anyways";
   }

   ATRACE_BEGIN("VoldNativeService::start");
   //启动与framework通讯的服务
   if (android::vold::VoldNativeService::start() != android::OK) {
       LOG(ERROR) << "Unable to start VoldNativeService";
       exit(1);
   }
   ATRACE_END();

   LOG(DEBUG) << "VoldNativeService::start() completed OK";

   ATRACE_BEGIN("NetlinkManager::start");
   //调用NetlinkManager start 方法    
   //稍后详细分析 3
   if (nm->start()) {
       PLOG(ERROR) << "Unable to start NetlinkManager";
       exit(1);
   }
   ATRACE_END();

   // This call should go after listeners are started to avoid
   // a deadlock between vold and init (see b/34278978 for details)
   //解析的参数设置到属性中
   android::base::SetProperty("vold.has_adoptable", has_adoptable ? "1" : "0");
   android::base::SetProperty("vold.has_quota", has_quota ? "1" : "0");
   android::base::SetProperty("vold.has_reserved", has_reserved ? "1" : "0");

   // Do coldboot here so it won't block booting,
   // also the cold boot is needed in case we have flash drive
   // connected before Vold launched
   coldboot("/sys/block");

   ATRACE_END();
 //将vold进程中主线程加入到线程池中
   android::IPCThreadState::self()->joinThreadPool();
   LOG(INFO) << "vold shutting down";

   exit(0);
}

通过以上代码分析我们总结其做了以下几件事:

1.创建/dev/block/vold目录

2.单例模式获取NetlinkManager对象并调用其start方法

3.解析fstab文件

4.调用VoldNativeService::start()方法,与framework通讯

5.单例模式获取VolumeManager对象并调用其start方法

接下来分析NetlinkManager中start方法,路径:system/vold/NetlinkManager.cpp

c 复制代码
int NetlinkManager::start() {
    struct sockaddr_nl nladdr;
    int sz = 64 * 1024;
    int on = 1;

    memset(&nladdr, 0, sizeof(nladdr));
    nladdr.nl_family = AF_NETLINK;
    nladdr.nl_pid = getpid();
    nladdr.nl_groups = 0xffffffff;
//创建socket客户端
    if ((mSock = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC,
            NETLINK_KOBJECT_UEVENT)) < 0) {
        PLOG(ERROR) << "Unable to create uevent socket";
        return -1;
    }

    // When running in a net/user namespace, SO_RCVBUFFORCE will fail because
    // it will check for the CAP_NET_ADMIN capability in the root namespace.
    // Try using SO_RCVBUF if that fails.
    if ((setsockopt(mSock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0) &&
        (setsockopt(mSock, SOL_SOCKET, SO_RCVBUF, &sz, sizeof(sz)) < 0)) {
        PLOG(ERROR) << "Unable to set uevent socket SO_RCVBUF/SO_RCVBUFFORCE option";
        goto out;
    }

    if (setsockopt(mSock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {
        PLOG(ERROR) << "Unable to set uevent socket SO_PASSCRED option";
        goto out;
    }
//绑定服务端
    if (bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) {
        PLOG(ERROR) << "Unable to bind uevent socket";
        goto out;
    }
//交给NetlinkHander处理通讯
    mHandler = new NetlinkHandler(mSock);
    if (mHandler->start()) {
        PLOG(ERROR) << "Unable to start NetlinkHandler";
        goto out;
    }

    return 0;
//关闭socket
out:
    close(mSock);
    return -1;
}

该方法处理很简单就是建立了Socket并交给其NetlinkHandler处理,调用其start方法,接下来看NetlinkHandler中做了什么

路径:system/vold/NetlinkHandler.cpp

c 复制代码
int NetlinkHandler::start() {
   //调用其父类SocketListener中的方法,开始监听服务端中的消息
   //消息会解析成NetlinkEvent对象作为参数并回调onEvent(NetlinkEvent *evt)方法
    return this->startListener();
}

void NetlinkHandler::onEvent(NetlinkEvent *evt) {
    VolumeManager *vm = VolumeManager::Instance();
    const char *subsys = evt->getSubsystem();

    if (!subsys) {
        LOG(WARNING) << "No subsystem found in netlink event";
        return;
    }
  // 如果subsys是block类型的就调用VolumeManager的handleBlockEvent方法处理
    if (std::string(subsys) == "block") {
        vm->handleBlockEvent(evt);
    }
}

通过以上代码分析NetlinkManager主要与驱动层建立Socket连接,接收存储卡的插拔事件传递给VolumeManager处理。

回到main.cpp中分析下怎么解析fstab文件的,先看下MTK9669中vendor/etc/fstab.m7642中的内容

第一列Src,下面方法解析中的rec->blk_device属性,用于匹配解析驱动穿过来的挂载的文件系统路径

第二列mnt_point,挂载点,外部存储卡挂载为auto

第三列类型,文件系统类型,外部存储卡为auto

第四列第五列为mnt_flags、fs_mgr_flags文件系统挂载标志位

c 复制代码
static int process_config(VolumeManager* vm, bool* has_adoptable, bool* has_quota,
                          bool* has_reserved) {
    ATRACE_NAME("process_config");
     //解析fstab文件获取fstab结构体对象
    fstab_default = fs_mgr_read_fstab_default();
    if (!fstab_default) {
        PLOG(ERROR) << "Failed to open default fstab";
        return -1;
    }

    /* Loop through entries looking for ones that vold manages */
    *has_adoptable = false;
    *has_quota = false;
    *has_reserved = false;
    //遍历每一行数据
    for (int i = 0; i < fstab_default->num_entries; i++) {
        auto rec = &fstab_default->recs[i];
        //fs_mgr_flags列是否包含了quota
        if (fs_mgr_is_quota(rec)) {
            *has_quota = true;
        }
        //reserved_size是否大于0
        if (rec->reserved_size > 0) {
            *has_reserved = true;
        }
         //fs_mgr_flags列是否有voldmanaged标志
        if (fs_mgr_is_voldmanaged(rec)) {
              //是否是不可移动的
            if (fs_mgr_is_nonremovable(rec)) {
                LOG(WARNING) << "nonremovable no longer supported; ignoring volume";
                continue;
            }

            std::string sysPattern(rec->blk_device);
            std::string nickname(rec->label);
			
         //add by liuxin debug
		   LOG(DEBUG) << "sysPattern="<<rec->blk_device<<",nickname="<<rec->label<<",mountPoint="<<rec->mount_point;
            int flags = 0;
           //fs_mgr_flags是否encryptable
            if (fs_mgr_is_encryptable(rec)) {
                flags |= android::vold::Disk::Flags::kAdoptable;
                *has_adoptable = true;
            }
            //没有主存储卡
            if (fs_mgr_is_noemulatedsd(rec)
                    || android::base::GetBoolProperty("vold.debug.default_primary", false)) {
                flags |= android::vold::Disk::Flags::kDefaultPrimary;
            }

//把解析的参数创建DiskSource对象添加到VolumeManager中
            vm->addDiskSource(std::shared_ptr<VolumeManager::DiskSource>(
                    new VolumeManager::DiskSource(sysPattern, nickname, flags)));
        }
    }
    return 0;
}

上面代码解析了fstabe文件设置了has_adoptable、has_quota 、has_reserved属性,并且fs_mgr_flags列是voldmanager解析处理创建DiskSource对象添加到VolumeManager中。

看打印如下:

接下来分析VoldNativeService的start()方法,VoldNativeService继承自BinderService,BinderService继承BBinder,所以它是Binder机制中的服务端程序

c 复制代码
status_t VoldNativeService::start() {
    IPCThreadState::self()->disableBackgroundScheduling(true);
    //注册当前客户端到binder驱动
    status_t ret = BinderService<VoldNativeService>::publish();
    if (ret != android::OK) {
        return ret;
    }
    //加入到binder线程池
    sp<ProcessState> ps(ProcessState::self());
    ps->startThreadPool();
    ps->giveThreadPoolName();
    return android::OK;
}

上述代码主要把当前的binder服务端加入到binder驱动中,方便提供给客户端调用

接下来看第五个步骤VolumeManager的start方法:

c 复制代码
int VolumeManager::start() {
    ATRACE_NAME("VolumeManager::start");

    // Always start from a clean slate by unmounting everything in
    // directories that we own, in case we crashed.
    //卸载掉所有的存储卡
    unmountAll();

    Devmapper::destroyAll();
    Loop::destroyAll();

    // Assume that we always have an emulated volume on internal
    // storage; the framework will decide if it should be mounted.
    CHECK(mInternalEmulated == nullptr);
    //创建内部存储卡
    mInternalEmulated = std::shared_ptr<android::vold::VolumeBase>(
            new android::vold::EmulatedVolume("/data/media"));
    mInternalEmulated->create();

    // Consider creating a virtual disk
    //虚拟存储卡不考虑
    updateVirtualDisk();

    return 0;
}

上面代码很简单,先卸载所有的存储卡,再创建了内部储存卡,其EmulateVolume关于挂载卸载的操作我们在下一篇文章中再介绍了。

总结

本篇文章介绍总体的挂载模块、Vold进程的入口main函数的详细分析,下一篇将介绍收到插拔事件如果管理存储卡信息和状态与Framework层通讯。
Android 9.0 Vold挂载流程解析(下)

相关推荐
刘信的csdn1 年前
Android 9.0 Vold挂载流程解析(下)
android u盘挂载流程·android 存储卡卸载流程·android 存储卡挂载流程·android vold进程