Android源码笔记--存储

Posted ljt2724960661

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android源码笔记--存储相关的知识,希望对你有一定的参考价值。

         这一节主要学习存储相关源码,android的存储系统主要由SystemSever进程中的MountService和Vold进程中的VolumeManager组成,它们管理着系统的存储设备,执行各种操作,包括mount、unmount、format等。在Android的存储系统中,MountService是为应用提供服务的Binder类,运行在SystemServer中,而StorageManager是MountServer的代理,在用户进程中使用的。Vold是一个守护进程,负责和底层存储系统的驱动交互。MountService和Vold之间通过socket进行通信,这个通信过程是双问的,有从MountService到Vold的操作命令,也有从Vold到MountServcie的消息,用来通知底层硬件发生了变化。

        Vold进程的主体是VolumeManager对象,它管理着系统底层所有Volume对象,实现各种存储相关的操作。NtelinkMananger对象的主要作用是创建NetlinkHandler对象。

1 管理存储设备——Vold 守护进程
          Vold 的全称是 Volume Daemon.用来管理各种存储设备,包括外置 USB和 SD卡设备,MountService 通过 Vold 进程查询和操作这些存储设备。如果外部存储设备发生变化,例如,插入了USB设备,Vold将会接收到内核的UEvent消息并转发给MountService。
  1.1 Vold的main函数
      Vold 也是通过 init进程启动,它在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

vold服务放到了core分组,这就意味着这系统启动时它就会被init进程启动。

vold模块的源码位于目录system/vold,先看看它的入口函数main(),代码如下:

/system/vold/main.cpp
 
int main(int argc, char** argv) 
    atrace_set_tracing_enabled(false);
    setenv("ANDROID_LOG_TAGS", "*:d", 1);  // Do not submit with verbose logs enabled
    android::base::InitLogging(argv, android::base::LogdLogger(android::base::SYSTEM));

    VolumeManager* vm;
    NetlinkManager* nm;
    parse_args(argc, argv);

    sehandle = selinux_android_file_context_handle();
    if (sehandle) 
        selinux_android_set_sehandle(sehandle);
    

    mkdir("/dev/block/vold", 0755);   //创建void目录

    /* For when cryptfs checks and mounts an encrypted filesystem */
    klog_set_level(6);

    /* Create our singleton managers */
    if (!(vm = VolumeManager::Instance()))                  //创建VolumeManager对象
        LOG(ERROR) << "Unable to create VolumeManager";
        exit(1);
    

    if (!(nm = NetlinkManager::Instance()))                  //创建NetlinkManager对象
        LOG(ERROR) << "Unable to create NetlinkManager";
        exit(1);
    

    if (android::base::GetBoolProperty("vold.debug", false)) 
        vm->setDebug(true);
    

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

    bool has_adoptable;
    bool has_quota;
    bool has_reserved;

    if (process_config(vm, &has_adoptable, &has_quota, &has_reserved)) 
        PLOG(ERROR) << "Error reading configuration... continuing anyways";
    

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

    ATRACE_BEGIN("VoldNativeService::start");
    if (android::vold::VoldNativeService::start() != android::OK)    //启动VoldNativeService
        LOG(ERROR) << "Unable to start VoldNativeService";
        exit(1);
    
    ATRACE_END();

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

    ATRACE_BEGIN("NetlinkManager::start");
    if (nm->start()) 
        PLOG(ERROR) << "Unable to start NetlinkManager";
        exit(1);
    
   ...

    // 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");   //创建/sys/block下的节点文件

    ATRACE_END();

    android::IPCThreadState::self()->joinThreadPool();
    LOG(INFO) << "vold shutting down";

    exit(0);

无论是VolumeManager对象还是NetlinkManager对象都是通过(aidl)跨进程通信。

1.2 监听驱动发出的消息——Vold的NetlinkManager 对象
            NetlinkManager对象主要的工作是临听驱动发出的 uevent 消息。main()函数中调用NetlinkManager类的静态函数Instance()来创建NetlinkManager对象,代码如下:

NetlinkManager* NetlinkManager::Instance() 
    if (!sInstance) sInstance = new NetlinkManager();
    return sInstance;

Instance()函数创建了NetlinkManager对象并通过静态变量sInstance来引用,这意味着vold进程中只会有一个NetlinkManager对象。NetlinkManager的构造函数如下所示:

NetlinkManager::NetlinkManager() 
    mBroadcaster = NULL;

NetlinkManager 的构造函数只是对变量 mBroadcaster 进行了初始化。main()函数中会调用NetlinkManager的setBroadcaster()函数来给变量mBroadcaster重新赋值。

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;



/system/vold/NetlinkHandler.cpp
 
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;
    

    if (std::string(subsys) == "block") 
        vm->handleBlockEvent(evt);
    
/system/vold/VolumeManager.cpp
 
void VolumeManager::handleBlockEvent(NetlinkEvent* evt) 
    std::lock_guard<std::mutex> lock(mLock);

    if (mDebug) 
        LOG(DEBUG) << "----------------";
        LOG(DEBUG) << "handleBlockEvent with action " << (int)evt->getAction();
        evt->dump();
    

    std::string eventPath(evt->findParam("DEVPATH") ? evt->findParam("DEVPATH") : "");
    std::string devType(evt->findParam("DEVTYPE") ? evt->findParam("DEVTYPE") : "");

    if (devType != "disk") return;

    int major = std::stoi(evt->findParam("MAJOR"));
    int minor = std::stoi(evt->findParam("MINOR"));
    dev_t device = makedev(major, minor);

    switch (evt->getAction()) 
        case NetlinkEvent::Action::kAdd: 
            for (const auto& source : mDiskSources) 
                if (source->matches(eventPath)) 
                    // For now, assume that MMC and virtio-blk (the latter is
                    // specific to virtual platforms; see Utils.cpp for details)
                    // devices are SD, and that everything else is USB
                    int flags = source->getFlags();
                    if (major == kMajorBlockMmc || IsVirtioBlkDevice(major)) 
                        flags |= android::vold::Disk::Flags::kSd;
                     else 
                        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: 
            LOG(DEBUG) << "Disk at " << major << ":" << minor << " changed";
            handleDiskChanged(device);
            break;
        
        case NetlinkEvent::Action::kRemove: 
            handleDiskRemoved(device);
            break;
        
        default: 
            LOG(WARNING) << "Unexpected block event action " << (int)evt->getAction();
            break;
        
    

以上是关于Android源码笔记--存储的主要内容,如果未能解决你的问题,请参考以下文章

Android源码笔记--电量

HTML+CSS大项目2:品优购项目笔记+源码(万字收藏)

Android Sqlite框架 GreenDao的源码分析笔记

Android Sqlite框架 GreenDao的源码分析笔记

聊聊架构--读书笔记

Android-Jetpack笔记--ViewModel