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

这篇具有很好参考价值的文章主要介绍了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层获取磁盘信息和状态。以下是其整体的模块框架图:
Android 9.0 Vold挂载流程解析(上),Android挂载流程,Android vold机制

从图中我们知道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

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

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

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中的内容
Android 9.0 Vold挂载流程解析(上),Android挂载流程,Android vold机制
第一列Src,下面方法解析中的rec->blk_device属性,用于匹配解析驱动穿过来的挂载的文件系统路径
第二列mnt_point,挂载点,外部存储卡挂载为auto
第三列类型,文件系统类型,外部存储卡为auto
第四列第五列为mnt_flags、fs_mgr_flags文件系统挂载标志位

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中。
看打印如下:
Android 9.0 Vold挂载流程解析(上),Android挂载流程,Android vold机制
接下来分析VoldNativeService的start()方法,VoldNativeService继承自BinderService,BinderService继承BBinder,所以它是Binder机制中的服务端程序

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方法:

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挂载流程解析(下)文章来源地址https://www.toymoban.com/news/detail-655644.html

到了这里,关于Android 9.0 Vold挂载流程解析(上)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Handler原理机制解析,Android开发中的重要性

    Handler在android程序开发中使用的非常频繁、我们知道android是不允许在子线程中更新UI的,这就需要借助Handler来实现,那么你是否想过为什么一定要这个这样子做呢?而且Handler的内部消息处理机制究竟是什么样的呢?Handler的原理是需要通过源代码才能说的清楚的,而且它处理

    2024年02月06日
    浏览(40)
  • Android源码解析--享元设计模式,handler消息传递机制(基于Android API 33 SDK分析)

    使用共享对象可有效地支持大量的细粒度的对象 核心:对象复用。 1.1 享元模式Demo 火车票购票Demo 缓存对象在一个Map中。下面我们还会分析 用法 跟进去 这就是最明显的一个享元设计模式。 Android 开发一个知识点:UI 不能够在子线程中更新。 我们跟进post函数 Handler 传递了一个

    2024年02月11日
    浏览(33)
  • Android应用启动流程:从启动到可交互的过程解析

    关于作者:CSDN内容合伙人、技术专家, 从零开始做日活千万级APP。 专注于分享各领域原创系列文章 ,擅长java后端、移动开发、人工智能等,希望大家多多支持。 我们继续总结学习 Android 基础知识 ,温故知新。 还是在多年前做系统应用开发的时候,通过编译源码学习了一

    2024年02月11日
    浏览(40)
  • Android 9.0 网络之netd详解

    一、DHCP流程   分析netd之前先了解一下网络自动获取IP流程,借鉴下图流程查看代码:  (1)WIFI扫描到可用网络后进行连接,代码路径:frameworksoptnetwifiservicejavacomandroidserverwifiWifiStateMachine.java      其中 transitionTo(mObtainingIpState) 即调用如下,根据当前wifi配置文件信

    2024年02月03日
    浏览(29)
  • Android 9.0 蓝牙功能之一:蓝牙设置

    本章节记录如何构建蓝牙设置。 注意蓝牙应用必须是 System App。 LocalBluetoothManager 是操作蓝牙的主要入口。 1.通过 LocalBluetoothManager,可以获取到LocalBluetoothAdapter;CachedBluetoothDeviceManager;BluetoothEventManager、LocalBluetoothProfileManager。 2.通过 BluetoothEventManager.registerCallback 注册回调,

    2023年04月24日
    浏览(44)
  • android 9.0 屏蔽系统所有通知功能实现

    目录 1.概述 2.屏蔽系统所有通知功能实现的核心类

    2024年02月11日
    浏览(47)
  • Android 9.0 系统关闭时区夏令时功能

    在9.0的系统rom定制化开发中,在开发国际化项目中,对于有些地区执行夏令时,导致时间对不上,也有可能 一个国家某些地区执行夏令时而一些国家不执行夏令时,导致时间不一样,所以为了避免麻烦,就关闭系统的夏令时功能, 夏令时会比正常时间晚一小时。这就需要分

    2023年04月16日
    浏览(54)
  • Android 9.0 无源码app增加授予相关权限

    在9.0的系统rom产品开发中,对于一些无源码app需要增加一些权限,比如悬浮窗权限,由于app内部没申请这个权限,所以需要系统适配默认授予这个权限, 就需要在PMS解析安装app的时候 授予悬浮窗权限就可以了 在pms管理解析安装app中,是通过PackageManage的getPackageArchiveInfo()实

    2024年02月02日
    浏览(43)
  • Android 9.0以上 连接wifi失败 解决方案

    Android9开始,WIFI那块的API发生了改变: addNetwork(WifiConfiguration config) 此方法在API级别Q中已弃用) 见addNetworkSuggestions(java.util.List), removeNetworkSuggestions(java.util.List)新的API添加Wi-Fi网络进行审议时,自动连接到无线网络。 兼容性注意:对于目标Build.VERSION_CODES.Q或更高的应用程序

    2024年02月12日
    浏览(41)
  • Android 9.0 禁用adb shell input输入功能

    在9.0的系统rom产品开发中,在进行一些定制开发中,对于一些adb shell功能需要通过属性来控制禁止使用input 等输入功能,比如adb shell input keyevent 响应输入事件等,所以就需要 熟悉adb shell input的输入事件流程,然后来禁用adb shell input的输入事件功能,接下来分析下adb shell inp

    2024年02月20日
    浏览(52)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包