Android之vold进程启动源码分析

article/2025/10/2 17:41:40

1.Vold (Volume Daemon)介绍

vold进程接收来自内核的外部设备消息,用于管理和控制Android平台外部存储设备,包括SD插拨、挂载、卸载、格式化等;当外部设备发生变化时,内核通过Netlink发送uEvent格式的消息给用户空间程序,Netlink 是一种基于异步通信机制,在内核与用户应用间进行双向数据传输的特殊 socket,用户态应用使用标准的socket API 就可以使用 netlink 提供的强大功能;

2.Vold 框架设计

Vold是native程序,用于管理和控制Android平台外部存储设备的管控中心,是一个后台运行的进程。它与Java层的MountService交互,Vold接收来自kernel的uevent消息,然后向上层转发,MountService接收来自vold的消息,同时也可以向vold发送控制命令。从以上Vold设计框架图中可以看到,Vold有三个模块,分别为NetlinkManager,VolumeManager,CommandListener。
NetlinkManager模块专门接收来自Linux内核uevent消息,并将消息转发给VolumeManager处理,VolumeManager模块接着又把相关信息通过CommandListener发送给MountService,MountService根据收到的消息会发送相应的处理命令给VolumeManager,VolumeManager接收到命令后直接对外部存储设备进行操作。
CommandListener模块内部封装良一个Socket用于跨进程通信,Java层的客户端MountService就是通过该Socket和服务端Vold进行通信的。

1.Netlink介绍

Netlink是Linux系统中用户空间进程和Kernel进行通信的一种机制,用户空间进程可以接收来自Kernel的消息,同时也可以向Kernel发送一些控制命令。 LINUX netlink机制一文中详细介绍了Netlink的用法。

2.Uevent介绍

uevent和Linux的设备文件系统及设备模型有关,是sysfs向用户空间发送的消息。消息格式实际上是一串字符串。当外部设备发生变化时,会引起Kernel发送Uevent消息;一般设备在/sys对应的目录下有个叫uevent的文件,往该文件里写入指定数据,也会触发Kernel发送和该设备相关的uevent消息,内核通过uevent告知外部存储系统发生的变化。

3.Vold 源码分析

 \system\vold\main.cpp
int main() 
{VolumeManager *vm;CommandListener *cl;NetlinkManager *nm;//创建vold设备文件夹mkdir("/dev/block/vold", 0755);//初始化Vold相关的类实例 singlevm = VolumeManager::Instance();nm = NetlinkManager::Instance();//CommandListener 创建vold socket监听上层消息cl = new CommandListener();vm->setBroadcaster((SocketListener *) cl);nm->setBroadcaster((SocketListener *) cl);//启动VolumeManager vm->start();//根据配置文件/etc/vold.fstab 初始化VolumeManager process_config(vm);//启动NetlinkManager socket监听内核发送ueventnm->start();//向/sys/block/目录下所有设备uevent文件写入“add\n”,//触发内核sysfs发送uevent消息coldboot("/sys/block");//启动CommandListener监听vold socketcl->startListener();// Eventually we'll become the monitoring threadwhile(1) {sleep(1000);}exit(0);
}
/etc/vold.fstab的内容如下:
<span style="background-color:#fefef2">#######################
## Regular device mount
##
## Format: dev_mount <label> <mount_point> <part> <sysfs_path1...>
## label        - Label for the volume
## mount_point  - Where the volume will be mounted
## part         - Partition # (1 based), or 'auto' for first usable partition.
## <sysfs_path> - List of sysfs paths to source devices
####################### Mounts the first usable partition of the specified device
#dev_mount sdcard /mnt/sdcard auto /block/mmcblk0
dev_mount internal /mnt/sdcard 19 /devices/platform/sprd-sdhci.3/mmc_host/mmc3
dev_mount sdcard /mnt/sdcard/external auto /devices/platform/sprd-sdhci.0/mmc_host/mmc0</span>

process_config解析vold.fstab文件:
static int process_config(VolumeManager *vm) {//打开vold.fstab的配置文件fp = fopen("/etc/vold.fstab", "r")//解析vold.fstab 配置存储设备的挂载点while(fgets(line, sizeof(line), fp)) {const char *delim = " \t";char *type, *label, *mount_point, *part, *mount_flags, *sysfs_path;type = strtok_r(line, delim, &save_ptr)label = strtok_r(NULL, delim, &save_ptr)mount_point = strtok_r(NULL, delim, &save_ptr)//判断分区 auto没有分区part = strtok_r(NULL, delim, &save_ptr)if (!strcmp(part, "auto")) {//创建DirectVolume对象 相关的挂载点设备的操作dv = new DirectVolume(vm, label, mount_point, -1);} else {dv = new DirectVolume(vm, label, mount_point, atoi(part));}//添加挂载点设备路径while ((sysfs_path = strtok_r(NULL, delim, &save_ptr))) {dv->addPath(sysfs_path)}//将DirectVolume 添加到VolumeManager管理vm->addVolume(dv);}fclose(fp);return 0;
}

4.Vold各模块分析

前面介绍了Vold包含NetlinkManager,VolumeManager,CommandListener三大模块,他们之间的关系如下:
接下来就分别针对每个模块进行详细分析。

1.NetlinkManager模块

NetlinkManager模块接收从Kernel发送的Uevent消息,解析转换成NetlinkEvent对象;再将此NetlinkEvent对象传递给VolumeManager处理。
启动流程
1)构造NetlinkManager实例:nm = NetlinkManager::Instance()
2)设置事件广播监听:nm->setBroadcaster((SocketListener *) cl)
3)启动NetlinkManager:nm->start()

构造NetlinkManager实例

NetlinkManager *NetlinkManager::Instance() {if (!sInstance) //采用单例模式创建NetlinkManager实例sInstance = new NetlinkManager();return sInstance;
}

启动NetlinkManager

int NetlinkManager::start() {//netlink使用的socket结构struct sockaddr_nl nladdr;//初始化socket数据结构memset(&nladdr, 0, sizeof(nladdr));nladdr.nl_family = AF_NETLINK;nladdr.nl_pid = getpid();nladdr.nl_groups = 0xffffffff;//创建socket PF_NETLINK类型mSock = socket(PF_NETLINK,SOCK_DGRAM,NETLINK_KOBJECT_UEVENT);//配置socket 大小setsockopt(mSock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz);setsockopt(mSock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on);//bindsocket地址bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr);//创建NetlinkHandler 传递socket标识,并启动mHandler = new NetlinkHandler(mSock);mHandler->start();return 0;
}
在启动NetlinkManager时,初始化socket用于创建NetlinkManager的属性变量mHandle实例,并启动NetlinkHandler,NetlinkHandler继承于NetlinkListener,NetlinkListener又继承于SocketListener,因此在构造NetlinkHandler实例时首先构造SocketListener及NetlinkListener,构造NetlinkListener对象的父类对象SocketListener:
SocketListener::SocketListener(int socketFd, bool listen) {init(NULL, socketFd, listen, false);
}
void SocketListener::init(const char *socketName, int socketFd, bool listen, bool useCmdNum) {mListen = listen;mSocketName = socketName;mSock = socketFd;mUseCmdNum = useCmdNum;pthread_mutex_init(&mClientsLock, NULL);mClients = new SocketClientCollection();
}
NetlinkListener构造函数:
NetlinkListener::NetlinkListener(int socket) :SocketListener(socket, false) {mFormat = NETLINK_FORMAT_ASCII;
}
NetlinkHandler构造函数:
NetlinkHandler::NetlinkHandler(int listenerSocket) :NetlinkListener(listenerSocket) {
}
因此构造NetlinkHandler实例过程仅仅创建良一个socket客户端连接。
NetlinkHandler start:
int NetlinkHandler::start() {//父类startListenerreturn this->startListener();
}
SocketListener  start:
int SocketListener::startListener() {//NetlinkHandler mListen为false if (mListen && listen(mSock, 4) < 0) {return -1;} else if (!mListen){//mListen为false 用于netlink消息监听//创建SocketClient作为SocketListener 的客户端 mClients->push_back(new SocketClient(mSock, false, mUseCmdNum));}//创建匿名管道pipe(mCtrlPipe);//创建线程执行函数threadStart    参thispthread_create(&mThread, NULL, SocketListener::threadStart, this);
}

uevent消息监听线程

启动NetlinkHandler过程通过创建一个SocketListener工作线程来监听Kernel netlink发送的UEvent消息,该线程完成的工作:
void *SocketListener::threadStart(void *obj) {//参数转换SocketListener *me = reinterpret_cast<SocketListener *>(obj);me->runListener();pthread_exit(NULL);return NULL;}
SocketListener 线程消息循环:
void SocketListener::runListener() {//SocketClient ListSocketClientCollection *pendingList = new SocketClientCollection();while(1) {fd_set read_fds;//mListen 为falseif (mListen) {max = mSock;FD_SET(mSock, &read_fds);}//加入一组文件描述符集合 选择fd最大的maxFD_SET(mCtrlPipe[0], &read_fds);pthread_mutex_lock(&mClientsLock);for (it = mClients->begin(); it != mClients->end(); ++it) {int fd = (*it)->getSocket();FD_SET(fd, &read_fds);if (fd > max)max = fd;}pthread_mutex_unlock(&mClientsLock);//监听文件描述符是否变化rc = select(max + 1, &read_fds, NULL, NULL, NULL);//匿名管道被写,退出线程if (FD_ISSET(mCtrlPipe[0], &read_fds))break;//mListen 为falseif (mListen && FD_ISSET(mSock, &read_fds)) {//mListen 为ture 表示正常监听socketstruct sockaddr addr;do {//接收客户端连接c = accept(mSock, &addr, &alen);} while (c < 0 && errno == EINTR);//此处创建一个客户端SocketClient加入mClients列表中,异步延迟处理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();//将所有有消息的Client加入到pendingList中pthread_mutex_lock(&mClientsLock);for (it = mClients->begin(); it != mClients->end(); ++it) {int fd = (*it)->getSocket();if (FD_ISSET(fd, &read_fds)) {pendingList->push_back(*it);}}pthread_mutex_unlock(&mClientsLock);//处理所有消息while (!pendingList->empty()) {it = pendingList->begin();SocketClient* c = *it;pendingList->erase(it);//处理有数据发送的socket 虚函数if (!onDataAvailable(c) && mListen) {//mListen为false}}}
}
在消息循环中调用onDataAvailable处理消息,onDataAvailable是个虚函数,NetlinkListener重写了此函数。
bool NetlinkListener::onDataAvailable(SocketClient *cli)
{//获取socket idint socket = cli->getSocket();//接收netlink uevent消息count = TEMP_FAILURE_RETRY(uevent_kernel_multicast_uid_recv(socket, mBuffer, sizeof(mBuffer), &uid));//解析uevent消息为NetlinkEvent消息NetlinkEvent *evt = new NetlinkEvent();evt->decode(mBuffer, count, mFormat);//处理NetlinkEvent onEvent虚函数onEvent(evt);
}
将接收的Uevent数据转化成NetlinkEvent数据,调用onEvent处理,NetlinkListener子类NetlinkHandler重写了此函数。
void NetlinkHandler::onEvent(NetlinkEvent *evt) {//获取VolumeManager实例VolumeManager *vm = VolumeManager::Instance();//设备类型const char *subsys = evt->getSubsystem();//将消息传递给VolumeManager处理if (!strcmp(subsys, "block")) {vm->handleBlockEvent(evt);}
}

NetlinkManager通过NetlinkHandler将接收到Kernel内核发送的Uenvet消息,转化成了NetlinkEvent结构数据传递给VolumeManager处理,uevent消息的上传流程:

2.VolumeManager模块

启动流程
1)构造VolumeManager对象实例
2)设置事件广播监听
3)启动VolumeManager
4)配置VolumeManager

VolumeManager类关系图:

DirectVolume是一个实体存储设备的抽象,通过系统调用直接操作存储设备。VolumeManager的SocketListenner与NetlinkManager的SocketListenner有所不同的:

NetlinkManager构造的SocketListenner:Kernel与Vold通信;

VolumeManager构造的SocketListenner:Native Vold与Framework MountService 通信;

NetlinkManager与VolumeManager交互流程图:

1.构造VolumeManager对象

VolumeManager *VolumeManager::Instance() {if (!sInstance)sInstance = new VolumeManager();return sInstance;
}VolumeManager::VolumeManager() {mDebug = false;mVolumes = new VolumeCollection();mActiveContainers = new AsecIdCollection();mBroadcaster = NULL;mUmsSharingCount = 0;mSavedDirtyRatio = -1;// set dirty ratio to 20 when UMS is activemUmsDirtyRatio = 20;mVolManagerDisabled = 0;
}

2.启动VolumeManager

int VolumeManager::start() {return 0;
}
VolumeManager启动过程什么都没有做。

3.uevent事件处理

前面NetlinkManager模块中介绍到,NetlinkHandler在onEvent函数中,将NetlinkEvent事件转交给VolumeManager处理:
void NetlinkHandler::onEvent(NetlinkEvent *evt) {……//将消息传递给VolumeManager处理if (!strcmp(subsys, "block")) {vm->handleBlockEvent(evt);}
}
    void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {//有状态变化设备路径const char *devpath = evt->findParam("DEVPATH");//遍历VolumeManager中所管理Volume对象(各存储设备代码抽象)for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {if (!(*it)->handleBlockEvent(evt)) {hit = true;break;}}
VolumeManager将消息交给各个DirectVolume对象处理:
int DirectVolume::handleBlockEvent(NetlinkEvent *evt) {//从NetlinkEvent消息中取出有状态变化设备路径const char *dp = evt->findParam("DEVPATH");PathCollection::iterator  it;//遍历所有的存储设备for (it = mPaths->begin(); it != mPaths->end(); ++it) {//根据存储设备路径进行匹配if (!strncmp(dp, *it, strlen(*it))) {/* 从NetlinkEvent消息中取出设备变化的动作 */int action = evt->getAction();/* 从NetlinkEvent消息中取出设备类型 */const char *devtype = evt->findParam("DEVTYPE");SLOGE("DirectVolume::handleBlockEvent() evt's DEVPATH= %s DEVTYPE= %s action= %d",dp, devtype, action);    //设备插入if (action == NetlinkEvent::NlActionAdd) {int major = atoi(evt->findParam("MAJOR"));int minor = atoi(evt->findParam("MINOR"));char nodepath[255];snprintf(nodepath,sizeof(nodepath), "/dev/block/vold/%d:%d",major, minor);SLOGE("DirectVolume::handleBlockEvent() NlActionAdd - /dev/block/vold/%d:%d\n", major, minor);if (createDeviceNode(nodepath, major, minor)) {SLOGE("Error making device node '%s' (%s)", nodepath,strerror(errno));}//新增磁盘if (!strcmp(devtype, "disk")) {handleDiskAdded(dp, evt);//新增分区} else {handlePartitionAdded(dp, evt);}//设备移除} else if (action == NetlinkEvent::NlActionRemove) {SLOGE("Volume  partition %d:%d removed",  atoi(evt->findParam("MAJOR")), atoi(evt->findParam("MINOR")));//删除磁盘if (!strcmp(devtype, "disk")) {handleDiskRemoved(dp, evt);//删除分区} else {handlePartitionRemoved(dp, evt);}//设备改变} else if (action == NetlinkEvent::NlActionChange) {//磁盘变化if (!strcmp(devtype, "disk")) {handleDiskChanged(dp, evt);//分区变化} else {handlePartitionChanged(dp, evt);}} else {SLOGW("Ignoring non add/remove/change event");}return 0;}}errno = ENODEV;return -1;
}

每一个Volume可能对应多个Path;即一个挂载点对应多个物理设备,因此VolumeManager中的每一个Volume对象都需要处理SD状态变换消息,当新增一个disk时:

void DirectVolume::handleDiskAdded(const char *devpath, NetlinkEvent *evt) {//主次设备号mDiskMajor = atoi(evt->findParam("MAJOR"));mDiskMinor = atoi(evt->findParam("MINOR"));//设备分区情况const char *tmp = evt->findParam("NPARTS");mDiskNumParts = atoi(tmp);if (mDiskNumParts == 0) {//没有分区,Volume状态为IdlesetState(Volume::State_Idle);} else {//有分区未加载,设置Volume状态PendingsetState(Volume::State_Pending);}//格式化通知msg:"Volume sdcard /mnt/sdcard disk inserted (179:0)"char msg[255];snprintf(msg, sizeof(msg), "Volume %s %s disk inserted (%d:%d)",getLabel(), getMountpoint(), mDiskMajor, mDiskMinor);//调用VolumeManager中的Broadcaster——>CommandListener 发送此msgmVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeDiskInserted,msg, false);
}
将新增一个disk以消息的方式通过CommandListener向MountService发送,由于CommandListener继承于FrameworkListener,而FrameworkListener又继承于SocketListener,CommandListener和FrameworkListener都没用重写父类的sendBroadcast方法,因此消息是通过 SocketListener的sendBroadcast函数向上层发送的,VolumeManager通知上层的消息流程图:
void SocketListener::sendBroadcast(int code, const char *msg, bool addErrno) 
{pthread_mutex_lock(&mClientsLock);//遍历所有的消息接收时创建的Client SocketClient// SocketClient将消息通过socket(“vold”)通信for (i = mClients->begin(); i != mClients->end(); ++i) {(*i)->sendMsg(code, msg, addErrno, false);}pthread_mutex_unlock(&mClientsLock);
}

3.CommandListener模块

1)构造CommandListener对象实例
2)调用startListener函数启动监听

1.构造CommandListener对象

CommandListener::CommandListener() :FrameworkListener("vold", true) {//注册Framework发送的相关命令 Command模式registerCmd(new DumpCmd());registerCmd(new VolumeCmd());registerCmd(new AsecCmd());registerCmd(new ObbCmd());registerCmd(new StorageCmd());registerCmd(new XwarpCmd());registerCmd(new CryptfsCmd());}
父类FrameworkListener构造:
FrameworkListener::FrameworkListener(const char *socketName, bool withSeq) :SocketListener(socketName, true, withSeq) {init(socketName, withSeq);
}
直接调用init函数;
void FrameworkListener::init(const char *socketName, bool withSeq) {mCommands = new FrameworkCommandCollection();errorRate = 0;mCommandCount = 0;mWithSeq = withSeq;
}
SocketListener的构造函数:
SocketListener::SocketListener(const char *socketName, bool listen, bool useCmdNum) {init(socketName, -1, listen, useCmdNum);
}
同样调用init函数进行初始化:
void SocketListener::init(const char *socketName, int socketFd, bool listen, bool useCmdNum) {mListen = listen;mSocketName = socketName;mSock = socketFd;mUseCmdNum = useCmdNum;pthread_mutex_init(&mClientsLock, NULL);mClients = new SocketClientCollection();
}
构造CommandListener对象过程中,首先注册了各种命令,并创建良一个socket客户端连接。命令注册过程:
void FrameworkListener::registerCmd(FrameworkCommand *cmd) {mCommands->push_back(cmd);
}
将各种命令存放到mCommand列表中。

2.启动CommandListener监听

int SocketListener::startListener() {//mSocketName = “Vold”mSock = android_get_control_socket(mSocketName);//NetlinkHandler mListen为true 监听socketif (mListen && < 0) {return -1;} else if (!mListen){mClients->push_back(new SocketClient(mSock, false, mUseCmdNum));}//创建匿名管道pipe(mCtrlPipe);//创建线程执行函数threadStart 参数thispthread_create(&mThread, NULL, SocketListener::threadStart, this);
}void *SocketListener::threadStart(void *obj) {SocketListener *me = reinterpret_cast<SocketListener *>(obj);me->runListener();
}void SocketListener::runListener() {//SocketClient ListSocketClientCollection *pendingList = new SocketClientCollection();while(1) {fd_set read_fds;//mListen 为trueif (mListen) {max = mSock;FD_SET(mSock, &read_fds);}//加入一组文件描述符集合 选择fd最大的max select有关FD_SET(mCtrlPipe[0], &read_fds);pthread_mutex_lock(&mClientsLock);for (it = mClients->begin(); it != mClients->end(); ++it) {int fd = (*it)->getSocket();FD_SET(fd, &read_fds);if (fd > max)max = fd;}pthread_mutex_unlock(&mClientsLock);//监听文件描述符是否变化rc = select(max + 1, &read_fds, NULL, NULL, NULL);//匿名管道被写,退出线程if (FD_ISSET(mCtrlPipe[0], &read_fds))break;//mListen 为trueif (mListen && FD_ISSET(mSock, &read_fds)) {//mListen 为ture 表示正常监听socketstruct sockaddr addr;do {c = accept(mSock, &addr, &alen);} while (c < 0 && errno == EINTR);//创建一个客户端SocketClient,加入mClients列表中 到异步延迟处理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();//将所有有消息的Client加入到pendingList中pthread_mutex_lock(&mClientsLock);for (it = mClients->begin(); it != mClients->end(); ++it) {int fd = (*it)->getSocket();if (FD_ISSET(fd, &read_fds)) {pendingList->push_back(*it);}}pthread_mutex_unlock(&mClientsLock);/* Process the pending list, since it is owned by the thread,*/while (!pendingList->empty()) {it = pendingList->begin();SocketClient* c = *it;//处理有数据发送的socket if (!onDataAvailable(c) && mListen) {//mListen为true……}}}
}

启动CommandListener监听过程其实就是创建一个监听的工作线程,用于监听客户端即MountService发过来的命令。

3.消息处理

当接收到MountService发送的消息时,将回调onDataAvailable函数进行处理。CommandListener父类FrameworkCommand重写了消息处理onDataAvailable函数。

bool FrameworkListener::onDataAvailable(SocketClient *c) {char buffer[255];//读取socket消息len = TEMP_FAILURE_RETRY(read(c->getSocket(), buffer, sizeof(buffer)));for (i = 0; i < len; i++) {if (buffer[i] == '\0') {//根据消息内容 派发命令dispatchCommand(c, buffer + offset);offset = i + 1;}}return true;
}void FrameworkListener::dispatchCommand(SocketClient *cli, char *data) {char *argv[FrameworkListener::CMD_ARGS_MAX];//解析消息内容 命令 参数……//执行对应的消息for (i = mCommands->begin(); i != mCommands->end(); ++i) {FrameworkCommand *c = *i;//匹配命令if (!strcmp(argv[0], c->getCommand())) {//执行命令c->runCommand(cli, argc, argv);goto out;}}
out:return;
}

对于VolumeCommand,其runCommand函数为:

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();int rc = 0;//查看存储设备if (!strcmp(argv[1], "list")) {return vm->listVolumes(cli);} else if (!strcmp(argv[1], "debug")) {if (argc != 3 || (argc == 3 && (strcmp(argv[2], "off") && strcmp(argv[2], "on")))) {cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume debug <off/on>", false);return 0;}vm->setDebug(!strcmp(argv[2], "on") ? true : false);//挂载存储设备} else if (!strcmp(argv[1], "mount")) {if (argc != 3) {cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume mount <path>", false);return 0;}rc = vm->mountVolume(argv[2]);//卸载存储设备} else if (!strcmp(argv[1], "unmount")) {if (argc < 3 || argc > 4 ||((argc == 4 && strcmp(argv[3], "force")) &&(argc == 4 && strcmp(argv[3], "force_and_revert")))) {cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume unmount <path> [force|force_and_revert]", false);return 0;}bool force = false;bool revert = false;if (argc >= 4 && !strcmp(argv[3], "force")) {force = true;} else if (argc >= 4 && !strcmp(argv[3], "force_and_revert")) {force = true;revert = true;}rc = vm->unmountVolume(argv[2], force, revert);//格式化存储设备} else if (!strcmp(argv[1], "format")) {if (argc != 3) {cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume format <path>", false);return 0;}rc = vm->formatVolume(argv[2]);//共享存储设备} else if (!strcmp(argv[1], "share")) {if (argc != 4) {cli->sendMsg(ResponseCode::CommandSyntaxError,"Usage: volume share <path> <method>", false);return 0;}rc = vm->shareVolume(argv[2], argv[3]);} else if (!strcmp(argv[1], "unshare")) {if (argc != 4) {cli->sendMsg(ResponseCode::CommandSyntaxError,"Usage: volume unshare <path> <method>", false);return 0;}rc = vm->unshareVolume(argv[2], argv[3]);} else if (!strcmp(argv[1], "shared")) {bool enabled = false;if (argc != 4) {cli->sendMsg(ResponseCode::CommandSyntaxError,"Usage: volume shared <path> <method>", false);return 0;}if (vm->shareEnabled(argv[2], argv[3], &enabled)) {cli->sendMsg(ResponseCode::OperationFailed, "Failed to determine share enable state", true);} else {cli->sendMsg(ResponseCode::ShareEnabledResult,(enabled ? "Share enabled" : "Share disabled"), false);}return 0;} else {cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown volume cmd", false);}if (!rc) {cli->sendMsg(ResponseCode::CommandOkay, "volume operation succeeded", false);} else {int erno = errno;rc = ResponseCode::convertFromErrno();cli->sendMsg(rc, "volume operation failed", true);}return 0;
}
针对不同的命令,调用VolumeManager的不同函数对存储设备进行操作,如挂载磁盘命令,则调用mountVolume函数:

int VolumeManager::mountVolume(const char *label) {//根据卷标查找VolumeVolume *v = lookupVolume(label);if (!v) {errno = ENOENT;return -1;}return v->mountVol();
}
调用Volume的mountVol函数来挂载设备。MountServcie发送命令的流程图:



 

整个Vold处理过程框架图如下:


http://chatgpt.dhexx.cn/article/jB2E2AD9.shtml

相关文章

<Android开发> Android vold - 第四篇 vold 的NetlinkHandler类简介

本系列主要介绍 Android vold&#xff0c;分为以下篇章 &#xff1c;Android开发&#xff1e; Android vold - 第一篇 vold前言简介 &#xff1c;Android开发&#xff1e; Android vold - 第二篇 vold 的main()函数简介 &#xff1c;Android开发&#xff1e; Android vold - 第…

<Android开发> Android vold - 第二篇 vold 的main()函数简介

本系列主要介绍 Android vold&#xff0c;分为以下篇章 &#xff1c;Android开发&#xff1e; Android vold - 第一篇 vold前言简介 &#xff1c;Android开发&#xff1e; Android vold - 第二篇 vold 的main()函数简介 &#xff1c;Android开发&#xff1e; Android vold - 第…

Android外部存储设备管理——vold挂载大容量存储设备

一、简介 Vold(volume Daemon)&#xff0c;即Volume守护进程&#xff0c;用来管理Android中存储类(USB-Storage&#xff0c;包含U盘和SD卡&#xff09;的热拔插事件&#xff0c;处于Kernel和Framework之间&#xff0c;是两个层级连接的桥梁。Vold在系统中以守护进程存在&#x…

Android Vold 架构简析

这篇文章中主要是分析一下&#xff0c;android系统里面的Vold——Vold是andorid系统的设备管理器&#xff0c;扮演着linux里面的udev的角色。它通过监听uevent的端口&#xff0c;取得 uevent事件&#xff0c;dispatch到 相应的Listener&#xff0c;执行相应的动作。 UEvent 在…

Android Vold架构

1. 总体架构 2. 流程概览 2.1 开启Vold 2.2 引导Uevent 2.3 处理事件 Vold - Volume Daemon存储类的守护进程&#xff0c;作为Android的一个本地服务&#xff0c;负责处理诸如SD、USB等存储类设备的插拔等事件。 1. 总体架构 Vold服务由volumeManager统一管控&#xff0c…

Vold 流程介绍

文章目录 前言框架MountService 流程Vold 流程 前言 印象中是参考 《深入理解 Android 卷 1 》 追的流程&#xff0c;差不多供参考吧 基于安卓 4.4 框架 MountService 流程 /*【初始化流程总结】&#xff1a; SystemServerinitAndLoop()// 创建 MountService 服务对象mountS…

ANDROID中的VOLD分析

现在可能很少有人会用mknod这个命令了&#xff0c;也很少有使用它的机会&#xff0c;但就在几年前&#xff0c;这还是一项linux工程师的必备技能&#xff0c;在制作文件系统前或加载新的驱动前&#xff0c;我们必须小心翼翼的创建设备节点。 不需要使用mknod并不是他消失了&am…

Android -- Vold机制简要分析

Android -- Vold机制简要分析 Vold是用于管理和控制Android外部存储介质的后台进程&#xff0c;这里说的管控&#xff0c;主要包括SD卡的插拔、挂载/卸载和格式化等&#xff1b;它是Android平台外部存储系统的管控枢纽。 Vold的整个控制模块主要由三个类模块构成&#xff1a;Ne…

Android Vold简介(一)

Vold(volume Daemon)&#xff0c;即Volume守护进程&#xff0c;用来管理Android中存储类的热拔插事件&#xff0c;处于Kernel和Framework之间&#xff0c;是两个层级连接的桥梁。先来看一下Vold在Android系统的整体架构。 该图主要包含了Framework和Vold进程的&#xff0c;Ke…

vold

一、Vold工作机制 Vold是Volume Daemon的缩写&#xff0c;它是Android平台中外部存储系统的管控中心&#xff0c;是管理和控制Android平台外部存储设备的后台进程。其功能主要包括&#xff1a;SD卡的插拔事件检测、SD卡挂载、卸载、格式化等。 如上图所示&#xff0c;Vold中的…

Vold工作流程分析学习

一 Vold工作机制分析 vold进程&#xff1a;管理和控制Android平台外部存储设备&#xff0c;包括SD插拨、挂载、卸载、格式化等&#xff1b; vold进程接收来自内核的外部设备消息。 Vold框架图如下&#xff1a; Vold接收来自内核的事件&#xff0c;通过netlink机制。 Netlink 是…

Android vold介绍

目录 1. 前言2. vold概述3. vold初始化|- -vm->start()|- -process_config|- -hardware::configureRpcThreadpool|- -vold::VoldNativeService::start|- -nm->start() 4. StorageManagerService|- -SM与vold建立关联|- - -startService(serviceClass) |- -StorageManager…

<Android开发> Android vold - 第一篇 vold前言简介

本系列主要介绍 Android vold&#xff0c;分为以下篇章 &#xff1c;Android开发&#xff1e; Android vold - 第一篇 vold前言简介 &#xff1c;Android开发&#xff1e; Android vold - 第二篇 vold 的main()函数简介 &#xff1c;Android开发&#xff1e; Android vold - 第…

Vold原理介绍

一、 Vold简介 Android中Vold是volume Daemon&#xff0c;即Volume守护进程&#xff0c;用来管理Android中存储类的热拔插事件。这里的热插拔涉及的场景如&#xff1a; 1. 手机usb以MTP或者传输照片方式插拔PC端后磁盘数据的挂卸载&#xff1b; 2. 设备开关机过程中存储设备各分…

C语言Switch....case用法

概述 C语言switch语句通常用于多个条件判断&#xff0c;根据不同情况执行不同的代码块。它的使用形式如下&#xff1a; switch&#xff08;表达式&#xff09; { case 常量表达式1&#xff1a; 语句序列1 break; case 常量表达式2&#xff1a; 语句序列2 break; ...... default…

MySQL 入门:Case 语句很好用

引言 MySQL CASE 是一个 MySQL 语句查询关键字&#xff0c;它定义了处理循环概念以执行条件集并使用 IF ELSE 返回匹配案例的方式。 MySQL 中的 CASE 是一种控制语句&#xff0c;它验证条件案例集&#xff0c;并在第一个案例满足 else 值时显示值并退出循环。 如果没有找到 T…

Shell 编程之 case 语句

一、case 语句 1、case 语句概述 (1)case 语句的作用 使用 case 语句改写 if 多分支可以使脚本结构更加清晰、层次分明。针对变量的不同取 值&#xff0c;执行不同的命令序列。 2、case 语句的结构: case 变量值 in 模式 1) 命令序列 1 ;; 模式 2) 命令序列 2 ;; *…

【shell】case实现简单的系统工具箱

case实现简单的系统工具箱 case实现简单的系统工具箱 #!/usr/bin/bash #system manage #by racon 2020-04-19menu() {cat <<-EOF########################################## h. help ## f. disk partition ## d. filesystem mount ## m. memory ## u. system lo…

SQL CASE语句的使用

SQL CASE语句的使用 CASE是一个控制流语句&#xff0c;其作用与IF-THEN-ELSE语句非常相似&#xff0c;可根据数据选择值。 CASE语句遍历条件并在满足第一个条件时返回值。 因此&#xff0c;一旦条件成立&#xff0c;它将短路&#xff0c;从而忽略后面的子句并返回结果。 正如我…

数据库 case 用法

【转载】:数据库中case when 的用法 CASE WHEN 及 SELECT CASE WHEN的用法Case具有两种格式。简单Case函数和Case搜索函数。 1.简单Case函数 CASE sex WHEN 1 THEN 男 WHEN 2 THEN 女 ELSE 其他 END 2.Case搜索函数 CASE WHEN sex 1 THEN 男 WHEN sex 2 THEN 女 ELSE 其他 …