Android磁盘之Vold启动

Android2024年1月3日 am8:08发布7个月前更新 3XCN.COM站长
0 0 0
广告也精彩
目录

前言

Volume Daemon,简写Vold,用于管理和控制Android平台外部存储设备的后台进程。这些管理或控制包括SD卡的插拔事件检测/SD卡挂载/卸载/格式化等。

记录一下Vold进程启动的源码分析,方便自己查阅。

Android P

这里很多都是网上的,我就走走流程。

正文

先看看vold哪里启动的。

这里主要涉及目录的代码

\system\vold

vold.rc

\system\vold\vold.rc
service vold /system/bin/vold \
        --blkid_context=u:r:blkid:s0 --blkid_untrusted_context=u:r:blkid_untrusted:s0 \
        --fsck_context=u:r:fsck:s0 --fsck_untrusted_context=u:r:fsck_untrusted:s0
    class core
    ioprio be 2
    writepid /dev/cpuset/foreground/tasks
    shutdown critical
    group root reserved_disk

至于何时加载,可以看看《init的启动》,init进程LoadBootScripts会添加/system/etc/init目录下的rc文件进行解析。

main.cpp

main()
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));
    VolumeManager *vm;
    NetlinkManager *nm;
    //解析参数,也就是vold.rc中带的
    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);
    klog_set_level(6);
    // 初始化VolumeManager
    if (!(vm = VolumeManager::Instance())) {
        exit(1);
    }
    //单例模式获取NetlinkManager对象
    if (!(nm = NetlinkManager::Instance())) {
        exit(1);
    }
    //设置是否打开VolumeManager中的日志,默认false
    if (android::base::GetBoolProperty("vold.debug", false)) {
        vm->setDebug(true);
    }
    //调用其start方法,
    if (vm->start()) {
        exit(1);
    }
    bool has_adoptable;
    bool has_quota;
    bool has_reserved;
    //解析fstab文件,该文件描述系统中各种文件系统的信息;我以MTK9669为例分析其fsab文件路径在vendor/etc/fstab.m7642
    if (process_config(vm, &has_adoptable, &has_quota, &has_reserved)) {
        PLOG(ERROR) << "Water_x Error reading configuration... continuing anyways";
    }
    //跟StorageManagerService通信
    if (android::vold::VoldNativeService::start() != android::OK) {
        exit(1);
    }
    //调用NetlinkManagerstart方法  
    if (nm->start()) {
        exit(1);
    }
    //解析的参数设置到属性中
    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");
    coldboot("/sys/block");
    //将vold进程中主线程加入到线程池中
    android::IPCThreadState::self()->joinThreadPool();
    exit(0);
}

这里主要做了如下核心工作:

  1. 初始化VolumeManager

  2. 初始化NetlinkManager

  3. 调用VolumeManager.start()

  4. 启动VoldNativeService::start() [跟StorageManagerService通信]

  5. 调用NetlinkManager.start()

下面就按照上面5个继续跟踪。

VolumeManager.cpp

通过单例模式初始化

Instance()
VolumeManager *VolumeManager::Instance() {
    if (!sInstance)
        sInstance = new VolumeManager();
    return sInstance;
}
VolumeManager()
VolumeManager::VolumeManager() {
    mDebug = false;
    mNextObbId = 0;
    mSecureKeyguardShowing = true;
}

NetlinkManager.cpp

这个也是单例模式

Instance()
NetlinkManager *NetlinkManager::Instance() {
    if (!sInstance)
        sInstance = new NetlinkManager();
    return sInstance;
}
NetlinkManager()
NetlinkManager::NetlinkManager() {
    mBroadcaster = NULL;
}

VolumeManager.cpp

start()
int VolumeManager::start() {
	//清楚所有状态
    unmountAll();
    Devmapper::destroyAll();
    Loop::destroyAll();
    CHECK(mInternalEmulated == nullptr);
	//创建/data/media的VolumeBase
    mInternalEmulated = std::shared_ptr<android::vold::VolumeBase>(
            new android::vold::EmulatedVolume("/data/media"));
    mInternalEmulated->create();
	//更新虚拟磁盘
	updateVirtualDisk();
    return 0;
}

VoldNativeService.cpp

start()
status_t VoldNativeService::start() {
    IPCThreadState::self()->disableBackgroundScheduling(true);
    //publish就是把该服务公开,并添加到ServiceManager,可以让其他客户端查询
    //具体看BinderService.h中publish()的定义
    status_t ret = BinderService<VoldNativeService>::publish();
    if (ret != android::OK) {
        return ret;
    }
    sp<ProcessState> ps(ProcessState::self());
    ps->startThreadPool();
    ps->giveThreadPoolName();
    return android::OK;
}

其中细节,具体看BinderService.h定定义哈

NetlinkManager.cpp

start()
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) {
        return -1;
    }
	//设置网络套接字属性
    if ((setsockopt(mSock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0) &&
        (setsockopt(mSock, SOL_SOCKET, SO_RCVBUF, &sz, sizeof(sz)) < 0)) {
        goto out;
    }
    if (setsockopt(mSock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {
        goto out;
    }
	//绑定服务端
    if (bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) {
        goto out;
    }
	//创建NetlinkHandler,并交给它处理通讯
    mHandler = new NetlinkHandler(mSock);
	//mHandler执行start()
    if (mHandler->start()) {
        goto out;
    }
    return 0;
out:
	//关闭socket
    close(mSock);
    return -1;
}

这里主要

  1. 创建socket,并绑定

  2. 创建NetlinkHandler,并start()

NetlinkHandler.h

这个目录:system\vold\NetlinkHandler.h

class NetlinkHandler: public NetlinkListener {

public:
    explicit NetlinkHandler(int listenerSocket);
    virtual ~NetlinkHandler();

    int start(void);
    int stop(void);

protected:
    virtual void onEvent(NetlinkEvent *evt);
};

NetlinkHandler.cpp

NetlinkHandler::NetlinkHandler(int listenerSocket) :
                NetlinkListener(listenerSocket) {
}

NetlinkHandler::~NetlinkHandler() {
}

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

int NetlinkHandler::stop() {
    return this->stopListener();
}

// 获取到 kernel 事件 后调用这个函数进行处理
void NetlinkHandler::onEvent(NetlinkEvent *evt) {
	//这里获取VolumeManager
    VolumeManager *vm = VolumeManager::Instance();
    const char *subsys = evt->getSubsystem();
    if (!subsys) {
        return;
    }
	// 如果subsys是block类型的就调用VolumeManager的handleBlockEvent方法处理
    if (std::string(subsys) == "block") {
        vm->handleBlockEvent(evt);
    }
}

这里会把kernel中事件上报到onEvent(),然后这里调用VolumeManager->handleBlockEvent()。

VolumeManager.cpp

handleBlockEvent()
void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {
	//申请一个lock
    std::lock_guard<std::mutex> lock(mLock);
	//在事件属性参数中查找设备的路径;
    std::string eventPath(evt->findParam("DEVPATH")?evt->findParam("DEVPATH"):"");
	//在事件属性参数中查找设备的类型;
    std::string devType(evt->findParam("DEVTYPE")?evt->findParam("DEVTYPE"):"");
	//判断是否是“disk”类型,磁盘设备,否的话,直接返回不做任何处理
    if (devType != "disk") return;
	//上报的数据中获取主设备号;
    int major = std::stoi(evt->findParam("MAJOR"));
	//上报的数据中获取次设备号;
    int minor = std::stoi(evt->findParam("MINOR"));
	//makedev()作用是将主次设备号联合得到具体可访问的设备对象索引;
    dev_t device = makedev(major, minor);
	//判断事件的动作类型
    switch (evt->getAction()) {
    case NetlinkEvent::Action::kAdd: {
    	//循环判断mDiskSources,这个mDiskSources 在vold的main()函数时就已经配置好的。所以mDiskSources是固定的一些数据。 
    	//在main()函数中调用了process_config()函数对VolumeManager::DiskSource进行赋值。具体是检索配置fstab文件,进行add操作。
        for (const auto& source : mDiskSources) {
			//从mDiskSources表获取的一个成员DiskSource类型的source,
			//调用该成员的matches函数对 第11行获取的设备路径eventPath,进行匹配字符串比较。
            if (source->matches(eventPath)) {
                // For now, assume that MMC and virtio-blk (the latter is
                // emulator-specific; see Disk.cpp for details) devices are SD,
                // and that everything else is USB
                int flags = source->getFlags();
				//判断主设备号是否是mmc的设备;
                if (major == kMajorBlockMmc
					//判断是否是模拟器运行的;
                    || (android::vold::IsRunningInEmulator()
                    //判断主设备号必须在 block设备范围内
                    && major >= (int) kMajorBlockExperimentalMin
                    && major <= (int) kMajorBlockExperimentalMax)) {
                    //将该磁盘Disk的flag标志为kSd
                    flags |= android::vold::Disk::Flags::kSd;
                } else {
					//将该磁盘Disk的flag标志为kUsb
                    flags |= android::vold::Disk::Flags::kUsb;
                }
                auto disk = new android::vold::Disk(eventPath, device,
                        source->getNickname(), flags);
                handleDiskAdded(std::shared_ptr<android::vold::Disk>(disk));
                break;
            }
        }
        break;
    }
    case NetlinkEvent::Action::kChange: {
        handleDiskChanged(device);
        break;
    }
    case NetlinkEvent::Action::kRemove: {
        handleDiskRemoved(device);
        break;
    }
    default: {
        break;
    }
    }
}

这里是event事件处理中心,主要处理disk类型事件。

上面分别有三种状态

  1. kAdd 挂载

  2. kChange

  3. kRemove 卸载

参考文章

  1. Android vold进程一 Vold启动和NetlinkManager数据获取

  2. Android P 储存设备挂载

  3. Android9.0版本Vold服务源码分析

 历史上的今天

版权声明 1、 本站名称: 91易搜
2、 本站网址: 91es.com3xcn.com
3、 本站文章: 部分来源于网络,仅供站长学习和参考,若侵权请留言
广告也精彩

相关文章

广告也精彩

暂无评论

评论审核已启用。您的评论可能需要一段时间后才能被显示。

暂无评论...

网站升级中

公告

近期网站升级中,可能存在一些bug。欢迎反馈 https://www.91es.com/we.html

本站域名

本站域名 : 91es.com3xcn.com。本站邮箱 : 站长邮箱 i@oorr.cn,通知邮箱we@oorr.cn ,如有更新,请看公告 。