Android12 U盘挂载流程学习(一)

VOLD(Volume Daemon)是 Android 系统中负责管理外部存储设备的守护进程,主要处理存储设备的挂载、卸载和格式化等操作。

主要功能

  1. 存储设备管理
  • 检测和识别外部存储设备(如 SD 卡、USB 存储设备)。
  • 处理设备的插入和移除事件。
  1. 挂载与卸载
  • 挂载存储设备到指定目录,使系统能够访问。
  • 卸载设备,确保数据安全移除。
  1. 文件系统支持
  • 支持多种文件系统(如 FAT32、exFAT、NTFS、ext4 等)。
  • 根据设备类型选择合适的文件系统进行挂载。
  1. 权限管理
  • 控制不同应用对存储设备的访问权限。
  • 确保用户数据的安全性和隐私。

Vold主要包含NetLinkManager(nm)、VolumeManager(vm)、VoldNativeService。

NetLinkManager:主要负责监听来自kernel的UEvent

VolumeManager:主要是配置相关的选项并告知上层,并接受上层所返回的消息

VoldNativeService:真正去实现挂载的服务,会创建相应的文件夹,设定U盘权限,是否开启FUSE等等

1. 卷管理

卷通常指的是存储设备或存储介质上的一个独立区域,用于存储文件和数据。在操作系统中,一个硬盘可以被分为多个分区,每个分区可以被格式化为一个独立的卷。用直白的话说就是卷是存储设备上的一部分,是可以直接拿来存储文件的。vold管理着存储设备 (比如SD卡、U盘) 所有的卷,其中卷又有虚拟卷 (EmulatedVolume) 、obb卷 (ObbVolume) 、私有卷 (PrivateVolume)、公有卷 (public Volume)、stub卷 (StubVolume)

2. Vold模块的启动

vold模块启动流程如下:

vold启动在init.rc中:

Java
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代码在/system/vold下面

函数入口是main函数:

Java
/system/vold/main.cpp
int main(int argc, char** argv) {
    ...
    VolumeManager* vm;
    NetlinkManager* nm;

    parse_args(argc, argv);

    sehandle = selinux_android_file_context_handle();
    if (sehandle) {
        selinux_android_set_sehandle(sehandle);
    }
    // 创建目录,用于放置后面建立的vold节点
    mkdir("/dev/block/vold", 0755);
    
    // VolumeManager负责Volume的一些管理
    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 (android::base::GetBoolProperty("vold.debug", false)) {
        vm->setDebug(true);
    }
    // 启动VolumeManager
    if (vm->start()) {
        PLOG(ERROR) << "Unable to start VolumeManager";
        exit(1);
    }

    VoldConfigs configs = {};
    // 解析fstab文件
    if (process_config(vm, &configs)) {
        PLOG(ERROR) << "Error reading configuration... continuing anyways";
    }

    android::hardware::configureRpcThreadpool(1, false /* callerWillJoin */);

    // 创建VoldNativeService
    if (android::vold::VoldNativeService::start() != android::OK) {
        LOG(ERROR) << "Unable to start VoldNativeService";
        exit(1);
    }
    ATRACE_END();

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

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

    android::IPCThreadState::self()->joinThreadPool();

    exit(0);
}

2.1 VolumeManager#start

Java
int VolumeManager::start() {
    ATRACE_NAME("VolumeManager::start");

    // 始终从头开始,卸载我们拥有的目录中的所有内容,以防崩溃
    unmountAll();

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

    CHECK(mInternalEmulatedVolumes.empty());
    // 构造出内置存储目录/data/media
    auto vol = std::shared_ptr<android::vold::VolumeBase>(
            new android::vold::EmulatedVolume("/data/media", 0));
    vol->setMountUserId(0);
    vol->create();
    mInternalEmulatedVolumes.push_back(vol);

    // 构造虚拟磁盘
    updateVirtualDisk();

    return 0;
}

2.2 VoldNativeService#start

Java
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负责连接vold与StorageManagerService

2.3 NetlinkManager#start

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

    // 注册UEVENT事件,用于接收内核信息
    if ((mSock = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_KOBJECT_UEVENT)) < 0) {
        PLOG(ERROR) << "Unable to create uevent socket";
        return -1;
    }
    
    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;
    }
    
    // NetlinkHandler用于对接收到的内核消息进行处理
    mHandler = new NetlinkHandler(mSock);
    // 开始监听内核消息
    if (mHandler->start()) {
        PLOG(ERROR) << "Unable to start NetlinkHandler";
        goto out;
    }

    return 0;

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

2.3.1 NetlinkHandler#start

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

这里的startListener是SocketListener的一个成员方法,NetlinkHandler继承了NetlinkListener,NetlinkListener继承了SocketListener:

2.3.1.1 SocketListener#startListener

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

int SocketListener::startListener(int backlog) {

    // mSocket在创建NetlinkHandler时赋值了
    if (!mSocketName && mSock == -1) {
        SLOGE("Failed to start unbound listener");
        errno = EINVAL;
        return -1;
    } else if (mSocketName) {
        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)
        mClients[mSock] = new SocketClient(mSock, false, mUseCmdNum);

    //建立管道,用于后面的关闭监听循环
    if (pipe2(mCtrlPipe, O_CLOEXEC)) {
        SLOGE("pipe failed (%s)", strerror(errno));
        return -1;
    }
    
    if (pthread_create(&mThread, nullptr, SocketListener::threadStart, this)) {
        SLOGE("pthread_create (%s)", strerror(errno));
        return -1;
    }

    return 0;
}

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

    me->runListener();
    pthread_exit(nullptr);
    return nullptr;
}

2.3.1.2 SocketListener#runListener

C++
void SocketListener::runListener() {
    while (true) {
        std::vector<pollfd> fds;

        pthread_mutex_lock(&mClientsLock);
        fds.reserve(2 + mClients.size());
        fds.push_back({.fd = mCtrlPipe[0], .events = POLLIN});
        if (mListen) fds.push_back({.fd = mSock, .events = POLLIN});
        for (auto pair : mClients) {
            // NB: calling out to an other object with mClientsLock held (safe)
            const int fd = pair.second->getSocket();
            if (fd != pair.first) SLOGE("fd mismatch: %d != %d", fd, pair.first);
            fds.push_back({.fd = fd, .events = POLLIN});
        }
        pthread_mutex_unlock(&mClientsLock);

        SLOGV("mListen=%d, mSocketName=%s", mListen, mSocketName);
        int rc = TEMP_FAILURE_RETRY(poll(fds.data(), fds.size(), -1));
        if (rc < 0) {
            SLOGE("poll failed (%s) mListen=%d", strerror(errno), mListen);
            sleep(1);
            continue;
        }

        if (fds[0].revents & (POLLIN | POLLERR)) {
            char c = CtrlPipe_Shutdown;
            TEMP_FAILURE_RETRY(read(mCtrlPipe[0], &c, 1));
            if (c == CtrlPipe_Shutdown) {
                break;
            }
            continue;
        }
        if (mListen && (fds[1].revents & (POLLIN | POLLERR))) {
            int c = TEMP_FAILURE_RETRY(accept4(mSock, nullptr, nullptr, SOCK_CLOEXEC));
            if (c < 0) {
                SLOGE("accept failed (%s)", strerror(errno));
                sleep(1);
                continue;
            }
            pthread_mutex_lock(&mClientsLock);
            mClients[c] = new SocketClient(c, true, mUseCmdNum);
            pthread_mutex_unlock(&mClientsLock);
        }

        // Add all active clients to the pending list first, so we can release
        // the lock before invoking the callbacks.
        std::vector<SocketClient*> pending;
        pthread_mutex_lock(&mClientsLock);
        const int size = fds.size();
        for (int i = mListen ? 2 : 1; i < size; ++i) {
            const struct pollfd& p = fds[i];
            if (p.revents & (POLLIN | POLLERR)) {
                auto it = mClients.find(p.fd);
                if (it == mClients.end()) {
                    SLOGE("fd vanished: %d", p.fd);
                    continue;
                }
                SocketClient* c = it->second;
                pending.push_back(c);
                c->incRef();
            }
        }
        pthread_mutex_unlock(&mClientsLock);

        for (SocketClient* c : pending) {
            // Process it, if false is returned, remove from the map
            SLOGV("processing fd %d", c->getSocket());
            // 处理消息
            if (!onDataAvailable(c)) {
                release(c, false);
            }
            c->decRef();
        }
    }
}

这里就是kernel与native通信的接口,内核上报u盘插入事件后就会通过这里通知到上层。

3. StorageManagerService的启动

StorageManagerService通过SystemServer启动,启动完成后调用ServiceManager.addService注册服务

C++
/frameworks/base/services/core/java/com/android/server/StorageManagerService.java
public void onStart() {
    mStorageManagerService = new StorageManagerService(getContext());
    publishBinderService("mount", mStorageManagerService);
    mStorageManagerService.start();
}

protected final void publishBinderService(String name, IBinder service,
            boolean allowIsolated, int dumpPriority) {
        ServiceManager.addService(name, service, allowIsolated, dumpPriority);
}

3.1 Start

C++
private void start() {
    // 连接文件系统监控服务
    connectStoraged();
    // 连接vold
    connectVold();
}

3.2 connectVold

C++
private void connectVold() {
    IBinder binder = ServiceManager.getService("vold");
    ...

    if (binder != null) {
        // 获取native层服务端索引
        mVold = IVold.Stub.asInterface(binder);
        try {
            // 设置监听
            mVold.setListener(mListener);
        } catch (RemoteException e) {
            mVold = null;
            Slog.w(TAG, "vold listener rejected; trying again", e);
        }
    } else {
        Slog.w(TAG, "vold not found; trying again");
    }

    if (mVold == null) {
        BackgroundThread.getHandler().postDelayed(() -> {
            connectVold();
        }, DateUtils.SECOND_IN_MILLIS);
    } else {
        restoreLocalUnlockedUsers();
        onDaemonConnected();
    }
}

3.2.1 VoldNativeService#setListener

这里通过mVold调用了VoldNativeService的setListener,在system/vold/binder/android/os/IVold.aidl文件中声明了mvold可以调用的函数。

C++
binder::Status VoldNativeService::setListener(
        const android::sp<android::os::IVoldListener>& listener) {
    ENFORCE_SYSTEM_OR_ROOT;
    ACQUIRE_LOCK;

    VolumeManager::Instance()->setListener(listener);
    return Ok();
}

VolumeManager.cpp
void setListener(android::sp<android::os::IVoldListener> listener) { mListener = listener; }

这里在VolumeManager里注册了一个监听回调,对应的监听事件在system/vold/binder/android/os/IVoldListener.aidl里:

C++
package android.os;

/** {@hide} */
oneway interface IVoldListener {
    void onDiskCreated(@utf8InCpp String diskId, int flags);
    void onDiskScanned(@utf8InCpp String diskId);
    void onDiskMetadataChanged(@utf8InCpp String diskId,
            long sizeBytes, @utf8InCpp String label, @utf8InCpp String sysPath);
    void onDiskDestroyed(@utf8InCpp String diskId);

    void onVolumeCreated(@utf8InCpp String volId,
            int type, @utf8InCpp String diskId, @utf8InCpp String partGuid, int userId);
    void onVolumeStateChanged(@utf8InCpp String volId, int state);
    void onVolumeMetadataChanged(@utf8InCpp String volId,
            @utf8InCpp String fsType, @utf8InCpp String fsUuid, @utf8InCpp String fsLabel);
    void onVolumePathChanged(@utf8InCpp String volId,
            @utf8InCpp String path);
    void onVolumeInternalPathChanged(@utf8InCpp String volId,
            @utf8InCpp String internalPath);
    void onVolumeDestroyed(@utf8InCpp String volId);
}

3.2.2 onDaemonConnected

onDaemonConnected会发送一个消息,最后调到handleDaemonConnected:

C++
private void handleDaemonConnected() {
    initIfBootedAndConnected();
    resetIfBootedAndConnected();

    // On an encrypted device we can't see system properties yet, so pull
    // the system locale out of the mount service.
    if ("".equals(VoldProperties.encrypt_progress().orElse(""))) {
        copyLocaleFromMountService();
    }
}

3.2.2.1 resetIfBootedAndConnected

C++
private void resetIfBootedAndConnected() {
    Slog.d(TAG, "Thinking about reset, mBootCompleted=" + mBootCompleted
            + ", mDaemonConnected=" + mDaemonConnected);
    // 等待启动完成并且连接上storage或vold守护服务
    if (mBootCompleted && mDaemonConnected) {
        ...
        try {
            ...
            Slog.i(TAG, "Resetting vold...");
            mVold.reset();
            Slog.i(TAG, "Reset vold");

            ...
            for (int userId : systemUnlockedUsers) {
                mVold.onUserStarted(userId);
                mStoraged.onUserStarted(userId);
            }
            ...
    }
}

3.2.2.2 VoldManager#reset

C++
int VolumeManager::reset() {
    // Tear down all existing disks/volumes and start from a blank slate so
    // newly connected framework hears all events.
    for (const auto& vol : mInternalEmulatedVolumes) {
        vol->destroy();
    }
    mInternalEmulatedVolumes.clear();
    // 更新已存在的disk
    for (const auto& disk : mDisks) {
        disk->destroy();
        disk->create();
    }
    // 更新virtualdisk
    updateVirtualDisk();
    mAddedUsers.clear();
    mStartedUsers.clear();
    return 0;
}

更新disk的目的是为了回调Framework这些disk已创建。

3.2.2.3 VoldManager#onUserStarted

C++
int VolumeManager::onUserStarted(userid_t userId) {
    LOG(INFO) << "onUserStarted: " << userId;

    if (mStartedUsers.find(userId) == mStartedUsers.end()) {
        createEmulatedVolumesForUser(userId);
    }

    mStartedUsers.insert(userId);

    createPendingDisksIfNeeded();
    return 0;
}

void VolumeManager::createPendingDisksIfNeeded() {

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值