Android Vold简介(一)

Vold(volume Daemon),即Volume守护进程,用来管理Android中存储类的热拔插事件,处于Kernel和Framework之间,是两个层级连接的桥梁。先来看一下Vold在Android系统的整体架构。
Android Vold简介(一)_第1张图片

该图主要包含了Framework和Vold进程的,Kernel和App层涉及的内容这里不再涉及,简单介绍一下。Vold主要是接收Kernel的uevent消息,然后通过NM(NetLinkManager)和VM(VolumeManager)处理,将消息传递到Framework的SM(StorageManager),最后SM会将数据存储下来,消息通知到在SM注册的服务和App。
 
Vold在系统中以守护进程存在,是一个单独的进程,首先来看下Vold的启动过程以及如何与Kernel和Framework建立的联系。
 
在init.rc中有start vold的命令会被init解析到,而start对应的函数do_start(const BuiltinArguments& args);即启动对应的service,对应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

接下来看一下vold的main函数(由于篇幅原因,只列出来部分主要过程),简要概括为以下几个过程:

  1. 初始化Log函数;
  2. 解析rc中的参数,创建vold块设备节点;
  3. 获取NM和VM单例对象;
  4. 启动NM、VoldNativeService和VM;
  5. 创建线程池,并进入循环,维持进程不退出;
int main(int argc, char** argv) {
    android::base::InitLogging(argv, android::base::LogdLogger(android::base::SYSTEM)); //初始化Log类
    VolumeManager* vm;
    NetlinkManager* nm;
    parse_args(argc, argv);//解析参数
    mkdir("/dev/block/vold", 0755);//创建vold节点,用来接收uevent消息;

    if (!(vm = VolumeManager::Instance())) {
        LOG(ERROR) << "Unable to create VolumeManager";
        exit(1);
    }

    if (!(nm = NetlinkManager::Instance())) {
        LOG(ERROR) << "Unable to create NetlinkManager";
        exit(1);
    }

    if (vm->start()) {   //启动vm
        PLOG(ERROR) << "Unable to start VolumeManager";
        exit(1);
    }

    android::hardware::configureRpcThreadpool(1, false /* callerWillJoin */);
    ATRACE_BEGIN("VoldNativeService::start");
    if (android::vold::VoldNativeService::start() != android::OK) {  //启动aidl接口
        LOG(ERROR) << "Unable to start VoldNativeService";
        exit(1);
    }
   if (nm->start()) { //启动nm
        PLOG(ERROR) << "Unable to start NetlinkManager";
        exit(1);
    }

    android::IPCThreadState::self()->joinThreadPool();  //进入循环
    LOG(INFO) << "vold shutting down";

    exit(0);
}

接下来着重看一下3个start函数分别都做了什么。首先看一下VM:

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;
}

从给到的注释来看,VM会先卸载掉对应文件夹中的所有东西,使之处于一个干净的状态,接着会构造出内置存储目录,也即/data/media,此处通过VolumeBase基类指针new了一个EmulatedVolume对象。在create函数中,执行了doCreate以及回调了onVolumeCreated,此处的listener则是SM服务,但是由于Vold启动较早,SystemServer还没有启动SM,所以这里getListener()得到的是空,后面SM启动完成后会重新触发。最后便是设置了当前存储设备的状态为unmounted。其中doCreate是虚函数,但是EmulatedVolume中并没有实现,所以最终还是调用了基类函数,也就直接返回了。最后根据给的注释可知,Vold会创建一个虚拟磁盘,即/data/misc/vold/virtual_disk。

status_t VolumeBase::create() {
    CHECK(!mCreated);

    mCreated = true;
    status_t res = doCreate();

    auto listener = getListener();
    if (listener) {
        listener->onVolumeCreated(getId(), static_cast<int32_t>(mType), mDiskId, mPartGuid);
    }

    setState(State::kUnmounted);
    return res;
}

status_t VolumeBase::doCreate() {
    return OK;
}

到这里,VM的启动过程基本上就结束了,至于/data/media的挂载过程放到后面的章节去阐述。接着按照顺序来看一下aidl接口的启动,连接着SM和vold。

status_t VoldNativeService::start() {
    IPCThreadState::self()->disableBackgroundScheduling(true);
    status_t ret = BinderService<VoldNativeService>::publish();
    if (ret != android::OK) {
        return ret;
    }
    sp<ProcessState> ps(ProcessState::self());
    ps->startThreadPool();
    ps->giveThreadPoolName();
    return android::OK;
}

启动的过程相对比较简单,VoldNativeService继承自BinderService,start主要注册了接口,使其他服务可以通过IVold可以找到,然后启动线程。
 
最后就是NM了,同样来看一下start函数,内部建立了一个socket连接,用于接收所有的uevent事件,最后会new一个NetlinkHandler对象,并执行start函数,然后会调用NetlinkListener父类的startListener函数去监听event。

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;
    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;
    }
    mHandler = new NetlinkHandler(mSock);
    if (mHandler->start()) {
        PLOG(ERROR) << "Unable to start NetlinkHandler";
        goto out;
    }
    return 0;
out:
    close(mSock);
    return -1;
}

到这里Vold的启动过程基本就结束了,后续Vold会监听kernel的uevent事件,然后处理转发通过Callback通知到SM,而Framework的服务以及App则可以通过SM去使用Vold处理Command。本篇着重讲了Vold进程的启动,下一篇着重看下各层级之间的联系是如何建立的。

你可能感兴趣的:(Android,Vold)