源码分析之存储系统启动流程Vold

Android的存储系统相对来讲还是比较复杂,其中主要包括了native层的Vold以及Java层的MountService。其中Vold在init进程中通过init脚本进行启动,而MountService则是在Java的服务总站SystemServer中配置启动的。它们之间的通信采用的Socket进行,而不是Binder机制,其主要的原因就是架构上比较简单,代码量也少。本文就从启动流程上分析安卓系统中的存储模块是如何加载起来的,下面就让我们直接进入正题。

Vold启动流程

native层的Vlod进程启动在init.rc脚本中进行配置的,其定义于 /system/core/rootdir/init.rc 中,我们看一下脚本文件内容。

init脚本相关配置

init.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
    socket vold stream 0660 root mount
    socket cryptd stream 0660 root mount
    ioprio be 2

脚本文件声明服务 service 为 vold,对应的程序文件路径 /system/bin/vold,系统级 core 核心服务。

Vold.main

init进程通过解析上述脚本文件内容,启动对应的Vold进程,进入到vold的main函数中。其函数文件位于 system/vold/main.cpp 中

// vold 启动时都创建了若干对象
int main(int argc, char** argv) {
    setenv("ANDROID_LOG_TAGS", "*:v", 1);
    android::base::InitLogging(argv, android::base::LogdLogger(android::base::SYSTEM));

    ...

    VolumeManager *vm;
    CommandListener *cl;
    CryptCommandListener *ccl;
    NetlinkManager *nm;

    //解析参数
    parse_args(argc, argv);

    ...

    // Quickly throw a CLOEXEC on the socket we just inherited from init
    fcntl(android_get_control_socket("vold"), F_SETFD, FD_CLOEXEC);
    fcntl(android_get_control_socket("cryptd"), F_SETFD, FD_CLOEXEC);

    mkdir("/dev/block/vold", 0755);

    // 用于cryptfs检查,并mount加密的文件系统
    klog_set_level(6);

    //创建单例对象 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);
    }

    if (property_get_bool("vold.debug", false)) {
        vm->setDebug(true);
    }

    // 创建 CommandListener 对象
    cl = new CommandListener();
    // 创建 CryptCommandListener 对象
    ccl = new CryptCommandListener();

    // 将新创建的 CommandListener 对象 sl 赋值给 vm 对象的成员变量 mBroadcaster
    vm->setBroadcaster((SocketListener *) cl);

    nm->setBroadcaster((SocketListener *) cl);

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

    if (process_config(vm)) {
        PLOG(ERROR) << "Error reading configuration... continuing anyways";
    }

    if (nm->start()) {
        PLOG(ERROR) << "Unable to start NetlinkManager";
        exit(1);
    }

    coldboot("/sys/block");
//    coldboot("/sys/class/switch");


    //启动响应命令的监听器
    if (cl->startListener()) {
        PLOG(ERROR) << "Unable to start CommandListener";
        exit(1);
    }

    if (ccl->startListener()) {
        PLOG(ERROR) << "Unable to start CryptCommandListener";
        exit(1);
    }

    //Vold成为监听线程
    while(1) {
        sleep(1000);
    }

    LOG(ERROR) << "Vold exiting";
    exit(0);
}

上述代码可以看出,Vold.main函数中主要做了以下几件事:

  • 解析传入参数
  • 创建 VolumeManager,设置监听并启动
  • 创建 NetlinkManager,设置监听并启动
  • 创建 CommandListener
  • 创建 CryptCommandListener
  • 循环成为监听线程

VM流程分析

VM初始化

VolumeManager是Vold进程中最重要的几个类之一,其简而言之就是Vold的统筹管理类,代码位于 /system/vold/VolumeBase.cpp 下,我们看一下其初始化流程。

// 单例模式
VolumeManager *VolumeManager::Instance() {
    if (!sInstance)
        sInstance = new VolumeManager();
    return sInstance;
}

VolumeManager::VolumeManager() {
    mDebug = false;
    mActiveContainers = new AsecIdCollection();
    mBroadcaster = NULL;
    mUmsSharingCount = 0;
    mSavedDirtyRatio = -1;
    // 当UMS获取时,则设置 dirty ratio 为 0
    mUmsDirtyRatio = 0;
}

VolumeManager类内部通过单例模式进行创建,创建同时创建AsecIdCollection负责aesc文件的收集,从析构函数中可以看出其被手动删除释放。下面便是设置监听。

VM->setBroadcaster

VolumeManager设置监听后,VM才可以开启,并且监听线程才能启动。其代码位于头文件中。

void setBroadcaster(SocketListener *sl) { mBroadcaster = sl; }

代码中,将CommandListener 对象sl赋值给 mBroadcaster。

VM->start

VolumeManager设置监听后,便开启工作。

int VolumeManager::start() {
    // Always start from a clean slate by unmounting everything in
    // directories that we own, in case we crashed.
    // 卸载所有设备,已提供最干净的环境
    unmountAll();

    // Assume that we always have an emulated volume on internal
    // storage; the framework will decide if it should be mounted.
    CHECK(mInternalEmulated == nullptr);

    // 创建Emulated内部存储
    // 其类型为 EmulatedVolume,设备路径为/data/media
    // id和label为“emulated”,mMountFlags=0
    // EmulatedVolume 继承于 VolumeBase
    mInternalEmulated = std::shared_ptr<android::vold::VolumeBase>(
            new android::vold::EmulatedVolume("/data/media"));

    // EmulatedVolume继承VolumeBase
    mInternalEmulated->create();

    return 0;
}

VolumeManager开启时候,会线卸载所有设备,保证干净的环境,之后在重新建立存储化境。

unmountAll卸载设备
int VolumeManager::unmountAll() {
    std::lock_guard<std::mutex> lock(mLock);

    // First, try gracefully unmounting all known devices
    // 1.卸载内部存储
    if (mInternalEmulated != nullptr) {
        mInternalEmulated->unmount();
    }

    // 2.卸载外部存储
    for (auto disk : mDisks) {
        disk->unmountAll();
    }

    // Worst case we might have some stale mounts lurking around, so
    // force unmount those just to be safe.
    // 有可能存在严重的潜在的旧的挂载设备存在,强力卸载以保证安全
    FILE* fp = setmntent("/proc/mounts", "r");
    if (fp == NULL) {
        SLOGE("Error opening /proc/mounts: %s", strerror(errno));
        return -errno;
    }

    // Some volumes can be stacked on each other, so force unmount in
    // reverse order to give us the best chance of success.
    std::list<std::string> toUnmount;
    mntent* mentry;
    while ((mentry = getmntent(fp)) != NULL) {
        if (strncmp(mentry->mnt_dir, "/mnt/", 5) == 0
                || strncmp(mentry->mnt_dir, "/storage/", 9) == 0) {
            toUnmount.push_front(std::string(mentry->mnt_dir));
        }
    }

    endmntent(fp);

    for (auto path : toUnmount) {
        SLOGW("Tearing down stale mount %s", path.c_str());
        android::vold::ForceUnmount(path);
    }

    return 0;
}

unmountAll中主要卸载系统内部和外部设备,以提供最干净的设备环境。先卸载内部设备,在遍历外部设备,遍历卸载,之后再针对其他情况卸载而外干扰设备。

其中mInternalEmulated设备为EmulatedVolume类型,其继承了父类VolumeBase,其子类调用unmount方法,优先走父类VolumeBase的方法,其内容如下:

status_t VolumeBase::unmount() {
    if (mState != State::kMounted) {
        LOG(WARNING) << getId() << " unmount requires state mounted";
        return -EBUSY;
    }

    // 设置状态,651,5
    setState(State::kEjecting);
    for (auto vol : mVolumes) {
        if (vol->destroy()) {
            LOG(WARNING) << getId() << " failed to destroy " << vol->getId()
                    << " stacked above";
        }
    }
    mVolumes.clear();
    status_t res = doUnmount();
    // 设置状态,发送 651,0
    setState(State::kUnmounted);
    return res;
}

父类的上述方法中,首先设置状态,其最终通过VM的方法,向Socket发送命令。其具体代码如下:

void VolumeBase::setState(State state) {
    mState = state;
    notifyEvent(ResponseCode::VolumeStateChanged, StringPrintf("%d", mState));
}

void VolumeBase::notifyEvent(int event) {
    if (mSilent) return;
    // 通过socket向MountService发送创建volume的命令(650)
    VolumeManager::Instance()->getBroadcaster()->sendBroadcast(event,
            getId().c_str(), false);
}

其次是调用子类的doUnmount方法,其对应到实现的子类自己的方法,这里的子类为EmulatedVolume,其对应的实现方法如下:

status_t EmulatedVolume::doUnmount() {
    if (mFusePid > 0) {
        kill(mFusePid, SIGTERM);
        TEMP_FAILURE_RETRY(waitpid(mFusePid, nullptr, 0));
        mFusePid = 0;
    }

    // 强制卸载fuse路径
    ForceUnmount(mFuseDefault);
    ForceUnmount(mFuseRead);
    ForceUnmount(mFuseWrite);

    rmdir(mFuseDefault.c_str());
    rmdir(mFuseRead.c_str());
    rmdir(mFuseWrite.c_str());

    mFuseDefault.clear();
    mFuseRead.clear();
    mFuseWrite.clear();

    return OK;
}

其内部具体的卸载方法就不一一细看了。最终,在再一次设置状态。到此内部设备就完成卸载,下面是外部设备的卸载过程。

status_t Disk::unmountAll() {
    for (auto vol : mVolumes) {
        vol->unmount();
    }
    return OK;
}

其通过遍历,调用所有Disk的unmount实现卸载操作,这里就不一一分析了。其具体内容可以参考GitYuan博客内容。

博客推荐

EmulatedVolume->create

EmulatedVolume设备的create方法,首先走父类的VolumeBase的create方法,如下:

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

    mCreated = true;
    status_t res = doCreate();
    // 通知VolumeCreated事件,发送650
    notifyEvent(ResponseCode::VolumeCreated,
            StringPrintf("%d \"%s\" \"%s\"", mType, mDiskId.c_str(), mPartGuid.c_str()));
    // 设置为非挂载状态,发送651,0
    setState(State::kUnmounted);
    return res;
}

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

父类中检查状态后,直接调用doCreate方法,之后通过VM的Socket发送消息到MountService中。至此,VolumeManager便启动完成。

NM流程分析

NM初始化

Vold.main中初始化VM后,便初始化NM,如下:

// 同样是单利模式获取
NetlinkManager *NetlinkManager::Instance() {
    if (!sInstance)
        sInstance = new NetlinkManager();
    return sInstance;
}

NetlinkManager::NetlinkManager() {
    mBroadcaster = NULL;
}

同样是单例模式进行实例化对象,之后便启动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;

    // 记录当前进程的pid
    nladdr.nl_pid = getpid();
    nladdr.nl_groups = 0xffffffff;

    // 创建 event socket
    if ((mSock = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC,
            NETLINK_KOBJECT_UEVENT)) < 0) {
        SLOGE("Unable to create uevent socket: %s", strerror(errno));
        return -1;
    }

    // 设置 uevent 的 SO_RCVBUFFORCE 选项
    if (setsockopt(mSock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0) {
        SLOGE("Unable to set uevent socket SO_RCVBUFFORCE option: %s", strerror(errno));
        goto out;
    }

    // 设置 uevent 的 SO_PASSCRED 选项
    if (setsockopt(mSock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {
        SLOGE("Unable to set uevent socket SO_PASSCRED option: %s", strerror(errno));
        goto out;
    }

    // 绑定 uevent socket
    if (bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) {
        SLOGE("Unable to bind uevent socket: %s", strerror(errno));
        goto out;
    }

    // 在 NetlinkManager 启动中创建 NetlinkHandler
    mHandler = new NetlinkHandler(mSock);
    if (mHandler->start()) {
        SLOGE("Unable to start NetlinkHandler: %s", strerror(errno));
        goto out;
    }

    return 0;

out:
    close(mSock);
    return -1;
}

其中内容比较多,最后我们发现其start时候,新建了一个NetlinkHandler负责通信。下面我们具体看看内部流程。

NH流程分析

NH初始化

NetlinkHandler为NetlinkManager内部的handler,负责通信操作,具体如下:

// NetlinkHandler继承于 NetlinkListener,NetlinkListener 继承于 SocketListener
// new NetlinkHandler(mSock) 中参数 mSock 是用于与 Kernel 进行通信的 socket 对象
// 由于这个继承关系,当 NetlinkHandler 初始化时会调用基类的初始化
NetlinkHandler::NetlinkHandler(int listenerSocket) :
                NetlinkListener(listenerSocket) {
}

int NetlinkHandler::start() {
    return this->startListener();
}

其中如注释所写,NetlinkHandler继承于 NetlinkListener,NetlinkListener 继承于 SocketListener,我们看一下其父类和爷爷类:

NetlinkListener::NetlinkListener(int socket) :
                            SocketListener(socket, false) {
    mFormat = NETLINK_FORMAT_ASCII;
}

SocketListener::SocketListener(const char *socketName, bool listen) {
    init(socketName, -1, listen, false);
}

// 通过层层继承调用至此(SocketListener <- NetlinkListener <- NetlinkHandler <- NetlinkManager)
void SocketListener::init(const char *socketName, int socketFd, bool listen, bool useCmdNum) {
    mListen = listen;
    mSocketName = socketName;
    // 用于监听 Kernel 发送过程的 uevent 事件
    mSock = socketFd;
    mUseCmdNum = useCmdNum;
    // 初始化同步锁
    pthread_mutex_init(&mClientsLock, NULL);
    // 创建 socket 通信的 client 端
    mClients = new SocketClientCollection();
}

由此最终走到了SocketListener,其最终实现监听kernel发送过来的uevent事件,当然最终上层调用的开始监听也是在这里最终实现,后下面分析到这里会具体分析。

NH->start

NH初始化完成后,便进入start状态。代码跟踪如下:

int NetlinkHandler::start() {
    return this->startListener();
}

然后调用父类的方法,这里只在爷爷类SocketListener发现其实现代码,如下:

int SocketListener::startListener(int backlog) {

    if (!mSocketName && mSock == -1) {
        SLOGE("Failed to start unbound listener");
        errno = EINVAL;
        return -1;
    } else if (mSocketName) {
        // 获取所对应的 socket 的句柄
        if ((mSock = android_get_control_socket(mSocketName)) < 0) {
            SLOGE("Obtaining file descriptor socket '%s' failed: %s",
                mSocketName, strerror(errno));
            return -1;
        }
        SLOGV("got mSock = %d for %s", mSock, mSocketName);
        fcntl(mSock, F_SETFD, FD_CLOEXEC);
    }

    // 开始监听
    if (mListen && listen(mSock, backlog) < 0) {
        SLOGE("Unable to listen on socket (%s)", strerror(errno));
        return -1;
    } else if (!mListen)
        // 创建 SocketClient 对象,并加入到 mClients 队列
        mClients->push_back(new SocketClient(mSock, false, mUseCmdNum));

    // 创建匿名管道
    // 这是一个二元数组,mCtrlPipe[0]从管道读数据,mCtrlPipe[1]从管道写数据
    if (pipe(mCtrlPipe)) {
        SLOGE("pipe failed (%s)", strerror(errno));
        return -1;
    }

    // 创建工作线程,线程运行函数threadStart
    if (pthread_create(&mThread, NULL, SocketListener::threadStart, this)) {
        SLOGE("pthread_create (%s)", strerror(errno));
        return -1;
    }

    return 0;
}

在SocketListener开始监听中,其创建SocketClient对象,加入到mClients队列中,然后对二元数组管道进行读写,最终通过pthread_create另外开启一个线程进行监听。线程代码开启如下:

void *SocketListener::threadStart(void *obj) {
    SocketListener *me = reinterpret_cast<SocketListener *>(obj);

    //开始监听
    me->runListener();

    // 线程退出
    pthread_exit(NULL);
    return NULL;
}

void SocketListener::runListener() {

    SocketClientCollection pendingList;

    while(1) {
        SocketClientCollection::iterator it;
        fd_set read_fds;
        int rc = 0;
        int max = -1;

        FD_ZERO(&read_fds);

        if (mListen) {
            max = mSock;
            FD_SET(mSock, &read_fds);
        }

        FD_SET(mCtrlPipe[0], &read_fds);
        if (mCtrlPipe[0] > max)
            max = mCtrlPipe[0];

        pthread_mutex_lock(&mClientsLock);
        for (it = mClients->begin(); it != mClients->end(); ++it) {
            // NB: calling out to an other object with mClientsLock held (safe)
            int fd = (*it)->getSocket();
            FD_SET(fd, &read_fds);
            if (fd > max) {
                max = fd;
            }
        }
        pthread_mutex_unlock(&mClientsLock);
        SLOGV("mListen=%d, max=%d, mSocketName=%s", mListen, max, mSocketName);
        if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) {
            if (errno == EINTR)
                continue;
            SLOGE("select failed (%s) mListen=%d, max=%d", strerror(errno), mListen, max);
            sleep(1);
            continue;
        } else if (!rc)
            continue;

        if (FD_ISSET(mCtrlPipe[0], &read_fds)) {
            char c = CtrlPipe_Shutdown;
            TEMP_FAILURE_RETRY(read(mCtrlPipe[0], &c, 1));
            if (c == CtrlPipe_Shutdown) {
                break;
            }
            continue;
        }
        if (mListen && FD_ISSET(mSock, &read_fds)) {
            struct sockaddr addr;
            socklen_t alen;
            int c;

            do {
                alen = sizeof(addr);
                c = accept(mSock, &addr, &alen);
                SLOGV("%s got %d from accept", mSocketName, c);
            } while (c < 0 && errno == EINTR);
            if (c < 0) {
                SLOGE("accept failed (%s)", strerror(errno));
                sleep(1);
                continue;
            }
            fcntl(c, F_SETFD, FD_CLOEXEC);
            pthread_mutex_lock(&mClientsLock);
            mClients->push_back(new SocketClient(c, true, mUseCmdNum));
            pthread_mutex_unlock(&mClientsLock);
        }

        /* Add all active clients to the pending list first */
        pendingList.clear();
        pthread_mutex_lock(&mClientsLock);
        for (it = mClients->begin(); it != mClients->end(); ++it) {
            SocketClient* c = *it;
            // NB: calling out to an other object with mClientsLock held (safe)
            int fd = c->getSocket();
            if (FD_ISSET(fd, &read_fds)) {
                pendingList.push_back(c);
                c->incRef();
            }
        }
        pthread_mutex_unlock(&mClientsLock);

        /* Process the pending list, since it is owned by the thread,
        * there is no need to lock it */
        while (!pendingList.empty()) {
            /* Pop the first item from the list */
            it = pendingList.begin();
            SocketClient* c = *it;
            pendingList.erase(it);
            /* Process it, if false is returned, remove from list */
            if (!onDataAvailable(c)) {
                release(c, false);
            }
            c->decRef();
        }
    }
}

runListener中,通过死循环和加锁机制,不断读取上述二元数组内的数据,最终将读写到的数据通过方法onDataAvailable实现回调。

SL->onDataAvailable

这里我们不妨多看看其回调过程,其SocketListener本身没有实现这个方法,其直接子类NetlinkListener实现了,如下:

// 父类 SocketListener 回调此方法
bool NetlinkListener::onDataAvailable(SocketClient *cli)
{
    int socket = cli->getSocket();
    ssize_t count;
    uid_t uid = -1;

    bool require_group = true;
    if (mFormat == NETLINK_FORMAT_BINARY_UNICAST) {
        require_group = false;
    }

    // 多次尝试获取socket数据
    count = TEMP_FAILURE_RETRY(uevent_kernel_recv(socket,
            mBuffer, sizeof(mBuffer), require_group, &uid));
    if (count < 0) {
        if (uid > 0)
            LOG_EVENT_INT(65537, uid);
        SLOGE("recvmsg failed (%s)", strerror(errno));
        return false;
    }

    NetlinkEvent *evt = new NetlinkEvent();
    // 解析消息并封装成 NetlinkEvent
    if (evt->decode(mBuffer, count, mFormat)) {
        //事件处理
        onEvent(evt);
    } else if (mFormat != NETLINK_FORMAT_BINARY) {
        // Don't complain if parseBinaryNetlinkMessage returns false. That can
        // just mean that the buffer contained no messages we're interested in.
        SLOGE("Error decoding NetlinkEvent");
    }

    delete evt;
    return true;
}

NetlinkListener在得到父类传来的数据后,将数据进行封装NetlinkEvent。最终实现onEvent方法回调。这里的onEvent接口是在哪声明的呢?根据头文件我们发现,其是一个虚函数,需要子类进行实现,其声明如下:

-> /system/vold/NetlinkHandler.h

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

由于NetlinkHandler为NetlinkListener的子类,我们查看发现其具体实现如下:

// NetlinkListener 在 onDataAvailable 回调到此方法
void NetlinkHandler::onEvent(NetlinkEvent *evt) {
    VolumeManager *vm = VolumeManager::Instance();
    const char *subsys = evt->getSubsystem();

    if (!subsys) {
        SLOGW("No subsystem found in netlink event");
        return;
    }

    if (!strcmp(subsys, "block")) {
        // 调用 VolumeManager 处理块设备
        vm->handleBlockEvent(evt);
    }
}

到这里,最终调用VolumeManager的handleBlockEvent实现处理。至此我们先告一段落,在后面存储系统工作流程中进行具体分析。

CommandListener流程分析

CL初始化

分析完程VM和NM的流程,下面便是CommandListener的实例化过程,如下:

CommandListener::CommandListener() :
                FrameworkListener("vold", true) {

    // 加入到 mCommands 队列
    registerCmd(new DumpCmd());
    registerCmd(new VolumeCmd());
    registerCmd(new AsecCmd());
    registerCmd(new ObbCmd());
    registerCmd(new StorageCmd());
    registerCmd(new FstrimCmd());
    // MStar Android Patch Begin
    registerCmd(new ISOCmd());
    registerCmd(new SambaCmd());
    // MStar Android Patch End
}

void FrameworkListener::registerCmd(FrameworkCommand *cmd) {
    // 加入到mCommands队列
    mCommands->push_back(cmd);
}

CommandListener在实例化中,注册了各种设备的操作命令,例如DumpCmd,VolumCmd等,其父类FrameworkListener做了啥,我们查看一下:

FrameworkListener::FrameworkListener(const char *socketName) :
                            SocketListener(socketName, true, false) {
    init(socketName, false);
}

void FrameworkListener::init(const char *socketName UNUSED, bool withSeq) {
    mCommands = new FrameworkCommandCollection();
    errorRate = 0;
    mCommandCount = 0;
    mWithSeq = withSeq;
    mSkipToNextNullByte = false;
}

父类FrameworkListener初始化又新建了FrameworkCommandCollection,这是干嘛的呀?其通过typedef重声明定义如下:

typedef android::sysutils::List<FrameworkCommand *> FrameworkCommandCollection;

FrameworkCommand::FrameworkCommand(const char *cmd) {
    mCommand = cmd;
}
关于DumpCmd,VolumCmd等几种cmd的介绍

在这里有必要介绍这几种DumpCmd,VolumCmd之间的关系,例如VolumCmd继承自VoldCommand继承自FrameworkCommand,FrameworkCommand有一个重要的方法runCommand实现如下:

int FrameworkCommand::runCommand(SocketClient *c UNUSED, int argc UNUSED,
                                char **argv UNUSED) {
    SLOGW("Command %s has no run handler!", getCommand());
    errno = ENOSYS;
    return -1;
}

其中其没有必要的实现代码,我们继续通过继承关系向上追溯,发现其在CommandListener类中实现了具体代码,如下:

int CommandListener::VolumeCmd::runCommand(SocketClient *cli,
int argc, char **argv) {
dumpArgs(argc, argv, -1);

if (argc < 2) {
    cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
    return 0;
}

VolumeManager *vm = VolumeManager::Instance();
std::lock_guard<std::mutex> lock(vm->getLock());

std::string cmd(argv[1]);
if (cmd == "reset") {
    return sendGenericOkFail(cli, vm->reset());

}

...

} else if (cmd == "mount" && argc > 2) {
    // mount [volId] [flags] [user]
    std::string id(argv[2]);
    auto vol = vm->findVolume(id);
    if (vol == nullptr) {
        return cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown volume", false);
    }

    int mountFlags = (argc > 3) ? atoi(argv[3]) : 0;
    userid_t mountUserId = (argc > 4) ? atoi(argv[4]) : -1;

    vol->setMountFlags(mountFlags);
    vol->setMountUserId(mountUserId);

    // Mstar Android Patch Begin
    CommandListener::VolumeCmd::finished = false;
    CommandListener::VolumeCmd::res = 1;
    std::thread mThread(&CommandListener::VolumeCmd::doMount,this,vol);
    mThread.detach();

    int i = 0;
    // if mount time > 3S ,return fail
    while(i<6 && CommandListener::VolumeCmd::finished == false) {
        SLOGD("sleep 0.5s");
        usleep(500000); //sleep 0.5s
        i++;
    }

    if (mountFlags & android::vold::VolumeBase::MountFlags::kPrimary) {
        vm->setPrimary(vol);
    }
    return sendGenericOkFail(cli, CommandListener::VolumeCmd::res);
    // Mstar Android Patch End

} else if (cmd == "unmount" && argc > 2) {
    // unmount [volId]
    std::string id(argv[2]);
    auto vol = vm->findVolume(id);
    if (vol == nullptr) {
        return cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown volume", false);
    }

    return sendGenericOkFail(cli, vol->unmount());

} else if (cmd == "format" && argc > 3) {
    // format [volId] [fsType|auto]
    std::string id(argv[2]);
    std::string fsType(argv[3]);
    auto vol = vm->findVolume(id);
    if (vol == nullptr) {
        return cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown volume", false);
    }

    return sendGenericOkFail(cli, vol->format(fsType));

} 

...

return cli->sendMsg(ResponseCode::CommandSyntaxError, nullptr, false);

}
其中代码比较长,实现了各种针对Volume设备的各种操作,比如 挂载mount,格式化format等等。。。

CL->startListener

下面我们查看一下CommandListener的startListener方法,CommandListener没有实现此方法,但是其继承自FrameworkListener,FrameworkListener也没有实现,其又继承自SocketListener,最终由SocketListener实现,如下:

int SocketListener::startListener() {
    return startListener(4);
}

int SocketListener::startListener(int backlog) {

    if (!mSocketName && mSock == -1) {
        SLOGE("Failed to start unbound listener");
        errno = EINVAL;
        return -1;
    } else if (mSocketName) {
        // 获取所对应的 socket 的句柄
        if ((mSock = android_get_control_socket(mSocketName)) < 0) {
            SLOGE("Obtaining file descriptor socket '%s' failed: %s",
                mSocketName, strerror(errno));
            return -1;
        }
        SLOGV("got mSock = %d for %s", mSock, mSocketName);
        fcntl(mSock, F_SETFD, FD_CLOEXEC);
    }

    // 开始监听
    if (mListen && listen(mSock, backlog) < 0) {
        SLOGE("Unable to listen on socket (%s)", strerror(errno));
        return -1;
    } else if (!mListen)
        // 创建 SocketClient 对象,并加入到 mClients 队列
        mClients->push_back(new SocketClient(mSock, false, mUseCmdNum));

    // 创建匿名管道
    // 这是一个二元数组,mCtrlPipe[0]从管道读数据,mCtrlPipe[1]从管道写数据
    if (pipe(mCtrlPipe)) {
        SLOGE("pipe failed (%s)", strerror(errno));
        return -1;
    }

    // 创建工作线程,线程运行函数threadStart
    if (pthread_create(&mThread, NULL, SocketListener::threadStart, this)) {
        SLOGE("pthread_create (%s)", strerror(errno));
        return -1;
    }

    return 0;
}

至此,CommandListener的startListener就分析完毕。

CryptCommandListener流程分析

CLL初始化

CryptCommandListener的初始化流程和上述的CommandListener基本相似,这了我们粗略的看一下,有兴趣的读者自行查看:

CryptCommandListener::CryptCommandListener() :
FrameworkListener("cryptd", true) {
    registerCmd(new CryptfsCmd());
}

CryptCommandListener::CryptfsCmd::CryptfsCmd() :
                VoldCommand("cryptfs") {
}

通过额外的registerCmd注册CryptfsCmd命令,其具体的runCommand实现对应的操作,这里就不贴代码了。

CLL->startListener

当然CryptCommandListener也没有实现方法startListener,其最终还是通过SocketListener来实现的。具体参考上述流程。

相关类图

相信到此,如果你认真的看完第一遍并且是第一次看完的话,肯定是一头雾水,什么跟什么啊,这么多类,各种跳真的是烦。不急不急,这里我们引用一张类图还是有必要的,根据这张类图,在回过去看代码流程,你就能轻松的知道各个类之间的关系是如何的。

VM相关类图

VolumeManager作为Vold模块最重要的一个类,其承载了很多重要的工作流程,其中涉及到很多类,类中各种继承关系也很复杂,对着上述的类图就很容易理清各个类之间的关系了。

NM相关类图

NetLinkManager负责直接接收Kernel发来的uevent事件,其类之间的关系更是复杂,相信有这张类图后,在回溯到代码流程中就很清晰了。SocketListener为最重要的父类,其直接和Socket打交道,之后在分发到子类中处理,其大概可以分为两个部分,如下:

命令流程如下:

SocketListener发现Socket中有数据后,对数据进行封装(NetlinkEvent),通过dispatchCommand方法,将命令分别分发到指定的Cmd进行处理,各种Cmd的声明和处理流程在CommandListener中都有声明。其中各种Cmd相似的方法处理都由父类FrameworkCommand进行统一的抽象管理。

命令分发如下:

当然SocketListener得到数据后,还会通过onDataAvaiable进行回传,到Netlinkhandler中通过onEventh回传到VolumeManager进行处理。

其他

内容说明

本想一篇章写完Android存储系统中启动流程,其主要包括native层的Vold和Java层MountService。介于篇幅太长,下面会在独立篇章介绍MountService启动流程以及两者之间的通信过程,希望三篇博客可以结束这段痛苦的代码阅读之旅。

引用说明

此博客内容为作者实战编辑,并非随便的拷贝,内容参考学习GitYuan博客中内容,这里郑重说明一下。其链接见下面。

GitYuan博客推荐

坚持原创技术分享,您的支持将鼓励我继续创作!