Vold 介绍

Vold(volume Daemon),即Volume守护进程,用来管理Android中存储类的热拔插事件,处于Kernel和Framework之间,是两个层级连接的桥梁。vold 代码路径为: system/vold 和 /system/core/libsysutils/src

Vold 分析

分析代码时,首先要看编译脚本即Android.bp,通过Android.bp 可以看出代码的组织关系,如何编译的。可以看出核心是 vold 这个可执行文件,主要入口为main.cpp,那我们就分析 main.cpp

Android.bp 文件
cc_binary {name: "vold",defaults: ["vold_default_flags","vold_default_libs",],srcs: ["main.cpp"],static_libs: ["libvold"],init_rc: ["vold.rc","wait_for_keymaster.rc",],
}

1. main.cpp

可以看出,主要实例化 VolumeManager NetlinkManager,并调用 VolumeManager NetlinkManager VoldNativeService  onStart() 方法。

main.cpp
int main(int argc, char** argv) {// log初始化android::base::InitLogging(argv, android::base::LogdLogger(android::base::SYSTEM));VolumeManager *vm;NetlinkManager *nm;parse_args(argc, argv);//参数解析mkdir("/dev/block/vold", 0755);// 获取实例,并调用 start() 方法vm = VolumeManager::Instance();nm = NetlinkManager::Instance();vm->start();android::vold::VoldNativeService::start();nm->start();android::IPCThreadState::self()->joinThreadPool();
}

2. VolumeManager

system/vold/VolumeManager.cpp
int VolumeManager::start() {unmountAll();Devmapper::destroyAll();Loop::destroyAll();// 通过 EmulatedVolume 完成对 "/data/media" 初始化mInternalEmulated = std::shared_ptr<android::vold::VolumeBase>(new android::vold::EmulatedVolume("/data/media"));mInternalEmulated->create();updateVirtualDisk();
}

3. NetlinkManager

通过 Netlink 与 kernel 进行通信,并new NetlinkHandler对象,并调用 start()方法。

重点在 NetlinkHandler,该类集成关系如下:NetlinkHandler -> NetlinkListener -> SocketListener

system/vold/NetlinkManager.cpp
NetlinkManager *NetlinkManager::sInstance = NULL;
NetlinkManager *NetlinkManager::Instance() {if (!sInstance)sInstance = new NetlinkManager();return sInstance;
}int NetlinkManager::start() {//PF_NETLINK: Netlink 用于在内核模块与在用户地址空间中的进程之间传递消息mSock = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC,NETLINK_KOBJECT_UEVENT)setsockopt(mSock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz);setsockopt(mSock, SOL_SOCKET, SO_RCVBUF, &sz, sizeof(sz);setsockopt(mSock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr);//重点,new NetlinkHandler对象,并调用 start()方法mHandler = new NetlinkHandler(mSock);mHandler->start();
}

4. NetlinkHandler

NetlinkHandler 继承于 NetlinkListener,而NetlinkHandler start() 方法,调用 this->startListener();
该方法必然是父类 NetlinkListener 的方法,继续跟踪代码。

system/vold/NetlinkHandler.hclass NetlinkHandler: public NetlinkListener {public:int start(void);int stop(void);private:virtual void onEvent(NetlinkEvent *evt);}
system/vold/NetlinkHandler.cppNetlinkHandler::NetlinkHandler(int listenerSocket) :NetlinkListener(listenerSocket) {}int NetlinkHandler::start() {return this->startListener();}int NetlinkHandler::stop() {return this->stopListener();}void NetlinkHandler::onEvent(NetlinkEvent *evt) {VolumeManager *vm = VolumeManager::Instance();const char *subsys = evt->getSubsystem();if (std::string(subsys) == "block") {vm->handleBlockEvent(evt);}}

5.  NetlinkListener

NetlinkListener 继承于 NetlinkListener,而且NetlinkListener 没有实现 startListener方法,那么该方法应该是其父类实现,继续跟踪。

system/core/libsysutils/include/sysutils/NetlinkListener.hclass NetlinkListener : public SocketListener {virtual bool onDataAvailable(SocketClient *cli);virtual void onEvent(NetlinkEvent *evt) = 0;}system/core/libsysutils/src/NetlinkListener.cppNetlinkListener::NetlinkListener(int socket) :SocketListener(socket, false) {mFormat = NETLINK_FORMAT_ASCII;}bool NetlinkListener::onDataAvailable(SocketClient *cli){int socket = cli->getSocket();count = TEMP_FAILURE_RETRY(uevent_kernel_recv(socket,mBuffer, sizeof(mBuffer), require_group, &uid));NetlinkEvent *evt = new NetlinkEvent();if (evt->decode(mBuffer, count, mFormat)) {onEvent(evt);}}

6. SocketListener

终于找到 startListener()方法的实现类。startListener() 方法通过 pthread_create(&mThread, NULL, SocketListener::threadStart, this) 创建单独线程,线程执行方法为 threadStart(),所以会走到 threadStart()方法。

threadStart() 方法有调用 SocketListener类的 runListener() 方法,runListener() 方法主要通过 select() read() 方法 获取事件信息,并放入 pendingList 链表中,最后逐个调用链表元素中的 onDataAvailable() 方法,而该方法在 SocketListener 类中是纯虚函数,必须由子类进行实现,所以到 NetlinkListener 继续分析。

由 NetlinkListener 分析可知,其实现了 onDataAvailable() 方法,该方法 通过uevent_kernel_recv 获取 kernel 的uevent 事件,并最终调用 onEvent() 方法。同样 onEvent() 方法在 NetlinkListener 类中是纯虚函数,所以必须由其子类 NetlinkHandler 实现,所以到 NetlinkHandler 继续分析。

由 NetlinkHandler 分析可知,其实现了 onEvent() 方法,并通过 VolumeManager实例调用其 handleBlockEvent() 方法,我们到 VolumeManager类继续分析。

system/core/libsysutils/include/sysutils/SocketListener.hclass SocketListener {public:int startListener();int stopListener();protected:virtual bool onDataAvailable(SocketClient *c) = 0;private:static void *threadStart(void *obj);void runListener();void init(const char *socketName, int socketFd, bool listen, bool useCmdNum);}
system/core/libsysutils/src/SocketListener.cppvoid SocketListener::runListener() {SocketClientCollection pendingList;while(1){for (it = mClients->begin(); it != mClients->end(); ++it) {int fd = (*it)->getSocket();FD_SET(fd, &read_fds);}rc = select(max + 1, &read_fds, NULL, NULL, NULL)TEMP_FAILURE_RETRY(accept4(mSock, nullptr, nullptr, SOCK_CLOEXEC));mClients->push_back(new SocketClient(c, true, mUseCmdNum));for (it = mClients->begin(); it != mClients->end(); ++it) {SocketClient* c = *it;int fd = c->getSocket();if (FD_ISSET(fd, &read_fds)) {pendingList.push_back(c);}}while (!pendingList.empty()) {it = pendingList.begin();SocketClient* c = *it;onDataAvailable(c))}}}void *SocketListener::threadStart(void *obj) {SocketListener *me = reinterpret_cast<SocketListener *>(obj);me->runListener();}int SocketListener::startListener(int backlog) {if (mListen && listen(mSock, backlog) < 0) mClients->push_back(new SocketClient(mSock, false, mUseCmdNum));pthread_create(&mThread, NULL, SocketListener::threadStart, this)}

7. VolumeManager

VolumeManager 类 handleBlockEvent 根据 NetlinkEvent 类型不同调用不同的方法。类型有kAdd,kChange,kRemove,分别对应设备新增,设备变更,设备移除操作。以kAdd 为例分析,其调用 handleDiskAdded() 方法,该方法调用 <android::vold::Disk> 的 create()方法,继续进行跟踪。

system/vold/VolumeManager.cppvoid VolumeManager::handleDiskAdded(const std::shared_ptr<android::vold::Disk>& disk) {disk->create();mDisks.push_back(disk);}void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {switch (evt->getAction()) {case NetlinkEvent::Action::kAdd: {auto disk = new android::vold::Disk(eventPath, device,source->getNickname(), flags);handleDiskAdded(std::shared_ptr<android::vold::Disk>(disk));}case NetlinkEvent::Action::kChange: {handleDiskChanged(device);}case NetlinkEvent::Action::kRemove: {handleDiskRemoved(device);}}}

8. Disk.cpp

其中 create() 方法通过 VolumeManager::Instance()->getListener() 获取 listener 并调用 onDiskCreated() 通知到 java StorageManagerService中,这是如何实现的我们继续分析。

system/vold/model/Disk.cppstatus_t Disk::create() {CHECK(!mCreated);mCreated = true;auto listener = VolumeManager::Instance()->getListener();if (listener) listener->onDiskCreated(getId(), mFlags);readMetadata();readPartitions();return OK;}

9.  getListener 实现分析

可以看到 VolumeManager 中实现 getListener() 方法,但是也仅是返回了 mListerner 变量,该变量是在 setListener() 中设置的,通过函数参数可以看出其通过 AIDL 实现了这样的调用。

system/vold/VolumeManager.hvoid setListener(android::sp<android::os::IVoldListener> listener) { mListener = listener; }android::sp<android::os::IVoldListener> getListener() { return mListener; }void handleBlockEvent(NetlinkEvent *evt);

10.  IVold.aidl 接口

system/vold/binder/android/os/IVold.aidlpackage android.os;import android.os.IVoldListener;import android.os.IVoldTaskListener;interface IVold {void setListener(IVoldListener listener);void onUserAdded(int userId, int userSerial);void onUserRemoved(int userId);void mount(@utf8InCpp String volId, int mountFlags, int mountUserId);void unmount(@utf8InCpp String volId);void format(@utf8InCpp String volId, @utf8InCpp String fsType);void checkEncryption(@utf8InCpp String volId);void mkdirs(@utf8InCpp String path);void fbeEnable();void mountDefaultEncrypted();void unlockUserKey(int userId, int userSerial, @utf8InCpp String token, @utf8InCpp String secret);void lockUserKey(int userId);}

11. StorageManagerServie

StorageManagerServie 在connect() 方法中,通过ServiceManager获取 vold 服务,并获取到binder 对象 ,最后通过 setListener(mListener)方法,其中 mListener 为  private final IVoldListener mListener = new IVoldListener.Stub() ,所以在 Disk.cpp 中 listener 为 StorageManagerService 设置的 listener,其 listener->onDiskCreated(getId(), mFlags) 也会调用到 StorageManagerService 中 IVoldListener.Stub 中方法。

frameworks/base/services/core/java/com/android/server/StorageManagerService.javaimport android.os.IVold;import android.os.IVoldListener;import android.os.IVoldTaskListener;private void connect() {IBinder binder = ServiceManager.getService("storaged");mStoraged = IStoraged.Stub.asInterface(binder);binder = ServiceManager.getService("vold");mVold = IVold.Stub.asInterface(binder);mVold.setListener(mListener);onDaemonConnected();}private final IVoldListener mListener = new IVoldListener.Stub() {@Overridepublic void onDiskCreated(String diskId, int flags) {synchronized (mLock) {final String value = SystemProperties.get(StorageManager.PROP_ADOPTABLE);switch (value) {case "force_on":flags |= DiskInfo.FLAG_ADOPTABLE;break;case "force_off":flags &= ~DiskInfo.FLAG_ADOPTABLE;break;}mDisks.put(diskId, new DiskInfo(diskId, flags));}}@Overridepublic void onDiskScanned(String diskId) {synchronized (mLock) {final DiskInfo disk = mDisks.get(diskId);if (disk != null) {onDiskScannedLocked(disk);}}}@Overridepublic void onDiskMetadataChanged(String diskId, long sizeBytes, String label,String sysPath) {synchronized (mLock) {final DiskInfo disk = mDisks.get(diskId);if (disk != null) {disk.size = sizeBytes;disk.label = label;disk.sysPath = sysPath;}}}@Overridepublic void onDiskDestroyed(String diskId) {synchronized (mLock) {final DiskInfo disk = mDisks.remove(diskId);if (disk != null) {mCallbacks.notifyDiskDestroyed(disk);}}}@Overridepublic void onVolumeCreated(String volId, int type, String diskId, String partGuid) {synchronized (mLock) {final DiskInfo disk = mDisks.get(diskId);final VolumeInfo vol = new VolumeInfo(volId, type, disk, partGuid);mVolumes.put(volId, vol);onVolumeCreatedLocked(vol);}}@Overridepublic void onVolumeStateChanged(String volId, int state) {synchronized (mLock) {final VolumeInfo vol = mVolumes.get(volId);if (vol != null) {final int oldState = vol.state;final int newState = state;vol.state = newState;onVolumeStateChangedLocked(vol, oldState, newState);}}}}

Android 9.0 Vold 流程分析(-)相关推荐

  1. Android8.0(34)----Android 8.0 Settings流程分析与变动

    Android 8.0 Settings流程分析与变动 一,相比Android Settings 7.0 如下图,在7.0的基础上,去掉了7.0新加的侧滑菜单(可能是觉得有点鸡肋吧).多加了一级页面, ...

  2. Android 7.0 Keyguard流程分析

    在android 6.0 上Keyguard作为了SystemUI的一个库文件被引用,所以编译的时候不会出现Keyguard.apk这个文件,Keyguard也伴随着SystemUI的启动而启动,其中 ...

  3. Android 7.0系统启动流程分析

    随着Android版本的升级,aosp项目中的代码也有了些变化,本文基于Android 7.0分析Android系统启动流程.当我们按下电源键后,整个Android设备大体经过了一下过程:  今天我们 ...

  4. Android 8.0 recovery 流程分析

    这里主要分析non A/B模式下的recovery流程 A/B模式下的recovery在boot中 后续会不断补充,如果有疏漏或者错误的地方,请指出,共同学习,谢谢! 一.流程分析 首先列出recov ...

  5. AOSP Android 8.0 冷启动流程分析(二)

    前奏: Android系统虽然基于Linux系统的,但是由于Android属于嵌入式设备,并没有像PC那样的BISO程序,取而代之的是Bootloader----系统启动加载器. /boot : 存放 ...

  6. c++builder启动了怎么停止_App 竟然是这样跑起来的 —— Android App/Activity 启动流程分析...

    在我的上一篇文章: AJie:按下电源键后竟然发生了这一幕 -- Android 系统启动流程分析​zhuanlan.zhihu.com 我们分析了系统在开机以后的一系列行为,其中最后一阶段 AMS( ...

  7. android 屏幕旋转流程,android自动屏幕旋转流程分析.doc

    android自动屏幕旋转流程分析.doc android自动屏幕旋转流程分析 在android设置(Settings)中我们可以看到显示(display)下有一个自动屏幕旋转的checkbox, 如 ...

  8. Android 手机灭屏流程分析详解

    参考地址:https://www.jianshu.com/p/9241f3a91095 本篇文章主要介绍 Android 开发中的部分知识点,通过阅读本篇文章,您将收获以下内容: 1.前言 2.Pow ...

  9. android加载efi分区,高通Android UEFI XBL 代码流程分析

    高通Android UEFI XBL 代码流程分析 背景 之前学习的lk阶段点亮LCD的流程算是比较经典,但是高通已经推出了很多种基于UEFI方案的启动架构. 所以需要对这块比较新的技术进行学习.在学 ...

最新文章

  1. R配对卡方检验(McNemar‘s Test)
  2. 搭建本地LNMP开发环境(1)-VMware内安装debian
  3. C#枚举中的位运算权限分配浅谈
  4. R语言版本查询以及line 1 of `undefined.cases': bad value of `47.25' for attribute `A2'的解决
  5. 多线程导出excel高并发_大牛带你深入java多线程与高并发:JMH与Disruptor,确定能学会?...
  6. iOS 10 UserNotifications 框架解析
  7. 要么战胜,要么战死,绝不投降
  8. 1篇文章认识ZCCT在线认证,加入千人在线学习大军领取云计算资料包!
  9. python之输出语句
  10. 对比较器的使用方法的研究
  11. 全国各地将推广电子证照,取代一证通
  12. 怎么查看python下opencv版本
  13. 钛资本研究院:全球产业链重构下的芯片机遇
  14. 误入 GitHub 游戏区,意外地收获颇丰
  15. DHCP 客户端移动位置后无法获取IP地址的解决办法和原因分析
  16. 怎么实现MindMapper中剪贴画的添加
  17. 一起学Pandas系列基础篇---loc和iloc
  18. 1.1 Introduction中 Consumers官网剖析(博主推荐)
  19. 有符号二进制乘法及MATLAB有符号数16进制到2进制的转换问题
  20. oracle817字符集,Oracle817 版本 不同字符集之间的数据库导入 (转)

热门文章

  1. “翻船体”隐射问题多 微微网络电话化解社交之痛
  2. 俄罗斯和伊朗:两个国家支持的黑客组织曾经一度交战
  3. 对话微软小娜负责人:如何撬动移动生态系统?
  4. HBuilder mui入门教程——(5)登录和访问控制
  5. MLXG发微博16个字正式宣布退役。
  6. 自定义View之模仿AppleWatch手表
  7. SAI绘制飘逸渐变线条
  8. Freemarker模板判断比较
  9. 轻松学韩语初级第四课
  10. 重写hashcode