Android源码笔记--存储
admin
2024-04-21 11:38:12
0

         这一节主要学习存储相关源码,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.rcservice 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:s0class coreioprio be 2writepid /dev/cpuset/foreground/tasksshutdown criticalgroup root reserved_disk

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

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

/system/vold/main.cppint main(int argc, char** argv) {atrace_set_tracing_enabled(false);setenv("ANDROID_LOG_TAGS", "*:d", 1);  // Do not submit with verbose logs enabledandroid::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) {   //启动VoldNativeServiceLOG(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 launchedcoldboot("/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.cppvoid 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.cppvoid VolumeManager::handleBlockEvent(NetlinkEvent* evt) {std::lock_guard 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 USBint 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(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;}}
}

相关内容

热门资讯

在沈阳遇到刑事案件如何挑选合适... 随着公众法律意识的不断提升,遇到各类法律纠纷时寻求专业法律服务已经成为普遍选择,其中刑事案件因其涉及...
美股收评:三大指数齐涨,费城半... 7月22日,美股高开高走,三大指数集体收涨,纳指涨1.29%,标普500指数涨0.89%,道指涨0....
中际旭创:在港上市最高发行价不... 7月22日,中际旭创在港交所公告,将在香港发行5450万股,最高发行价每股1010港元。该公司最高融...
武契奇:未来争取出任政府总理 【环球时报驻塞尔维亚特约记者 任一弛 环球时报特约记者 任重】据塞尔维亚《政治报》21日报道,塞尔维...
ST葫芦娃,弄丢了“七色莲花”... 曾经照亮企业发展之路的“七色莲花”,如今已在一次次违规中悄然失落。文/每日资本论如果葫芦娃弄丢了能够...
AI驱动业绩狂飙 股价集体回落...   随着2026年半年度业绩预告的密集披露,被誉为深圳“存储五虎”的江波龙、佰维存储、德明利、大普微...
【特朗普“淡化”与伊朗谈判可能... 【特朗普“淡化”与伊朗谈判可能性,并称将在红海航运受威胁时出手】美国总统特朗普淡化近期与伊朗举行谈判...
伊朗最高联合军事指挥部:如果美... 伊朗最高联合军事指挥部:如果美国袭击伊朗核设施,地区内所有美国及其盟友的利益都将成为目标。
美伊冲突再起,以色列财长称:无... 近日,美伊冲突再起,今年2月底曾参与对伊打击的以色列,反而持续置身事外。 据美国有线电视新闻网(CN...
加拿大总理:将考虑所有选项应对... 当地时间7月21日,加拿大总理马克·卡尼表示,在美国关税宣布后,他已与美国总统特朗普通话。卡尼还表示...