逆水行舟用力撑,一篙松劲退千寻。这篇文章主要讲述Android7.0 Vold 进程工作机制分析之整体流程相关的知识,希望能为你提供帮助。
android7.0 Vold 进程工作机制分析之整体流程
一、Vold简介
Vold是Volume Daemon的缩写,负责管理和控制Android平台外部存储设备,
包括SD插拨、挂载、卸载、格式化等。它是通过init进程解析init.rc脚本所启动的进程.它处于Native层.
二、基础架构
这里引用Gityuan博客的一张图。
文章图片
SystermServer进程和Vold进程是通过Socket进行通信的,Vold进程和Kernel是通过Netlink 进行通信的,Netlink 是一种特殊的Socket。
相关介绍:Netlink是linux提供的用于内核和用户态进程之间的通信方式,也能用于用户空间的两个进程通信,通过这个机制, 位于用户空间的进程, 可接收来自Kernel的一些信息( 例如Vold中用到的USB或SD的插拔消息) , 同时应用层也可通过Netlink向Kernel发送一些控制命令。
先大体的简单介绍一下流程:
1.由SystemServer进程发起挂载/卸载请求 运行在SystemServer进程的MountService通过NativeDaemonConnector给CommandListener发送请求,CommandListener再通知VolumeManager进行实际操作
2.由Kernel发起挂载/卸载请求 Kernel通过Netlink发送请求(传递uevent)给NetlinkManager,NetlinkManager通过内部的线程NetlinkHandler交给VolumeManager进行实际操作,然后VolumeManager通过CommandListener通知MountService
在分别仔细介绍着两个流程之前, 了解下Vold进程的启动流程, 先把握整体流程再细化。
三、Vold进程启动流程
Vold进程代码路径:system/vold/
主要类的路径(方便查阅)
system/vold/目录下
main.cpp————————————system/vold/main.cpp
NetlinkManager.cpp———————–system/vold/NetlinkManager.cpp
NetlinkHandler.cpp————————system/vold/NetlinkHandler.cpp
VoldCommand.cpp————————system/vold/VoldCommand.cpp
VolumeBase.cpp—————————system/vold/VolumeBase.cpp
VolumeManager.cpp———————–system/vold/VolumeManager.cpp
system/core/libsysutils/src/目录下
SocketListener.cpp————————–system/core/libsysutils/src/SocketListener.cpp
NetlinkListener.cpp————————–system/core/libsysutils/src/NetlinkListener.cpp
FrameworkListener.cpp——————–system/core/libsysutils/src/FrameworkListener.cpp
FrameworkCommand.cpp——————system/core/libsysutils/src//FrameworkCommand.cpp
system/core/include/sysutils/目录下
对应着system/core/libsysutils/src/目录的h文件
贴上我绘制的时序图(缩放浏览器可以放大查看或者在新标签页打开)
文章图片
分步骤给大家详细介绍下:
1.main()
Vold进程代码位于system/vold/目录下,从main.cpp开始,后续的截图我只截取主要的代码
在main方法里,主要做以下几件事情
①初始化VolumeManager ,CommandListener ,NetlinkManager 三个类的实例
②给VolumeManager 和NetlinkManager 设置CommandListener 实例,用作后续监听两个Socket,用得是设计模式中的Command(命令)模式
③启动VolumeManager ,CommandListener ,NetlinkManager
④解析Vold的配置文件fstab
⑤做一次冷启动
int main(int argc, char** argv) {
......VolumeManager *vm;
CommandListener *cl;
NetlinkManager *nm;
//创建文件夹/dev/block/vold
mkdir("
/dev/block/vold"
, 0755);
//用于cryptfs检查,
并mount加密的文件系统
klog_set_level(6);
//获取VolumeManager的单例
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);
}//实例化
cl =
new CommandListener();
//设置socket监听对象
vm->
setBroadcaster((SocketListener *) cl);
nm->
setBroadcaster((SocketListener *) cl);
//启动VolumeManager
if (vm->
start()) {
PLOG(ERROR) <
<
"
Unable to start VolumeManager"
;
exit(1);
}//解析Vold的配置文件fstab,初始化VolumeManager
if (process_config(vm)) {
PLOG(ERROR) <
<
"
Error reading configuration... continuing anyways"
;
}//启动NetlinkManager
if (nm->
start()) {
PLOG(ERROR) <
<
"
Unable to start NetlinkManager"
;
exit(1);
}
// 冷启动,
vold错过了一些uevent,重新触发。向/sys/block的uevent文件写入”add\\n” 字符触发内核发送Uevent消息,
相当执行了一次热插拔。
coldboot("
/sys/block"
);
//启动CommandListener
if (cl->
startListener()) {
PLOG(ERROR) <
<
"
Unable to start CommandListener"
;
exit(1);
}
......
}
【Android7.0 Vold 进程工作机制分析之整体流程】第④步
如果vold.fstab解析无误, VolueManager将创建具体的Volume, 若vold.fstab解析不存在或者打开失败, Vold将会读取Linux内核中的参数, 此时如果参数中存在SDCARD(也就是SD的默认路径), VolumeManager则会创建AutoVolume, 如果不存在这个默认路径那么就不会创建。
它的格式对应如下:
type———————–挂载命令
lable———————–标签
mount_point ————挂载点
part ———————–第几个分区
sysfs_path—————设备的sysfs paths
sysfs_path可以有多个 part指定分区个数, 如果是auto没有分区
第⑤步
coldboot方法会调用do_coldboot方法,往/sys/block目录写入add\\n事件。
static void do_coldboot(DIR *d, int lvl) {
struct dirent *de;
int dfd, fd;
dfd =
dirfd(d);
fd =
openat(dfd, "
uevent"
, O_WRONLY | O_CLOEXEC);
if(fd >
=
0) {
//写入add\\n事件
write(fd, "
add\\n"
, 4);
close(fd);
}
2.new CommandListener()
前面有讲过,CommandListener是用来监听Socket的, 监听Vold与Framework层的进程通信。它的关系图如下:
文章图片
它继承自FrameworkListener,FrameworkListener继承自SocketListener.
路径:
CommandListener.cpp———————–system/vold/CommandListener.cpp
这一步创建CommandListener的实例, 则构造方法被调用
CommandListener::CommandListener() :FrameworkListener("
vold"
, true) {
//注册多条指令
registerCmd(new DumpCmd());
registerCmd(new VolumeCmd());
registerCmd(new AsecCmd());
registerCmd(new ObbCmd());
registerCmd(new StorageCmd());
registerCmd(new FstrimCmd());
registerCmd(new AppFuseCmd());
}
调用registerCmd方法,注册一些指令,重写的是父类的registerCmd方法
void FrameworkListener::registerCmd(FrameworkCommand *cmd) {
//添加元素
mCommands->
push_back(cmd);
}
会把指令添加到mCommands 中,mCommands 是FrameworkCommandCollection的实例,在FrameworkListener.h文件中声明的
class FrameworkListener : public SocketListener {
......
private:
FrameworkCommandCollection *mCommands;
......
}
这里附上一张NetlinkManager家族的简单类图, 帮助后续理解
文章图片
3.vm-> start()
启动VolumeManager
VolumeManager模块负责管理所有挂载的设备节点以及相关操作的实际执行,
路径:
VolumeManager.cpp———————–system/vold/VolumeManager.cpp
int VolumeManager::start() {//卸载所有设备
unmountAll();
//智能指针创建一个VolumeBase实例
mInternalEmulated =
std::shared_ptr<
android::vold::VolumeBase>
(
new android::vold::EmulatedVolume("
/data/media"
));
//调用create()方法
mInternalEmulated->
create();
return 0;
}
①卸载所有设备
②创建一个VolumeBase实例
③调用VolumeBase的create方法
这里附上一张VolumeManager家族的简单类图, 帮助后续理解
文章图片
看下第③个步骤
3.1 mInternalEmulated-> create()
status_t VolumeBase::create() {mCreated =
true;
status_t res =
doCreate();
//向VolumeManager发送VolumeCreated命令
notifyEvent(ResponseCode::VolumeCreated,StringPrintf("
%d \\"
%s\\"
\\"
%s\\"
"
, mType, mDiskId.c_str(), mPartGuid.c_str()));
//设置已卸载状态
setState(State::kUnmounted);
return res;
}
向VolumeManager发送了VolumeCreated的消息,然后设置状态为已卸载.
这个notifyEvent的实现如下
3.2 notifyEvent
void VolumeBase::notifyEvent(int event, const std::string&
value) {
if (mSilent) return;
VolumeManager::Instance()->
getBroadcaster()->
sendBroadcast(event,StringPrintf("
%s %s"
, getId().c_str(), value.c_str()).c_str(), false);
}
获取单例VolumeManager对象, 然后获取到SocketListener对象调用sendBroadcast方法
sendBroadcast方法的实现如下
在safelist列表中添加SocketClient,然后调用sendMsg方法
void SocketListener::sendBroadcast(int code, const char *msg, bool addErrno) {
SocketClientCollection safeList;
//首先添加所有活动的SockClient到安全列表中
safeList.clear();
for (i =
mClients->
begin();
i !=
mClients->
end();
+
+
i) {
SocketClient* c =
*i;
c->
incRef();
//添加
safeList.push_back(c);
}while (!safeList.empty()) {
/* Pop the first item from the list */
i =
safeList.begin();
SocketClient* c =
*i;
safeList.erase(i);
//调用SockClient的sendMSg方法发送消息
if (c->
sendMsg(code, msg, addErrno, false)) {
SLOGW("
Error sending broadcast (%s)"
, strerror(errno));
}
c->
decRef();
}
}
SockClient
路径:
SockClient.cpp————————system/core/libsysutils/src/SockClient.cpp
调用sendMsg方法经过层层跳转,到sendDataLockedv方法中,往Socket中写入信息
3.3 sendDataLockedv
int SocketClient::sendDataLockedv(struct iovec *iov, int iovcnt) {
......
for (;
;
) {
ssize_t rc =
TEMP_FAILURE_RETRY(
writev(mSocket, iov +
current, iovcnt - current));
......
}
写入到Socket之后,SystemServer中的MountService会收到, 后续再细讲.
4.nm-> start()
这一步启动NetlinkManager
NetlinkManager
路径:
NetlinkManager.cpp———————–system/vold/NetlinkManager.cpp
NetlinkManager模块接收从Kernel通过Netlink机制发送过来的Uevent消息, 解析转换成NetlinkEvent对象,再将此NetlinkEvent对象传递给VolumeManager处理。
start方法如下
int NetlinkManager::start() {
......
//创建Socket
if ((mSock =
socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC,
NETLINK_KOBJECT_UEVENT)) <
0) {
SLOGE("
Unable to create uevent socket: %s"
, strerror(errno));
return -1;
}
//设置Socket的SO_RCVBUFFORCE大小
if (setsockopt(mSock, SOL_SOCKET, SO_RCVBUFFORCE, &
sz, sizeof(sz)) <
0) {
SLOGE("
Unable to set uevent socket SO_RCVBUFFORCE option: %s"
, strerror(errno));
goto out;
}
//设置Socket的SO_PASSCRED大小
if (setsockopt(mSock, SOL_SOCKET, SO_PASSCRED, &
on, sizeof(on)) <
0) {
SLOGE("
Unable to set uevent socket SO_PASSCRED option: %s"
, strerror(errno));
goto out;
}
//绑定Socket
if (bind(mSock, (struct sockaddr *) &
nladdr, sizeof(nladdr)) <
0) {
SLOGE("
Unable to bind uevent socket: %s"
, strerror(errno));
goto out;
}//创建一个NetlinkHandler对象,
并把创建好的Socket句柄传给它。
mHandler =
new NetlinkHandler(mSock);
//启动NetlinkHandler
if (mHandler->
start()) {
SLOGE("
Unable to start NetlinkHandler: %s"
, strerror(errno));
goto out;
}
return 0;
......}
①创建Socket,为PF_NETLINK类型
②设置Socket的SO_RCVBUFFORCE(接受缓存区)小
③设置Socket的SO_PASSCRED大小
④创建一个NetlinkHandler对象, 并启动它
主要看第④步
4.1 mHandler-> start()
构造函数传入了mSock,然后调用了NetlinkHandler的start方法
看一下它的实现
路径:
NetlinkHandler.cpp———————–system/vold/NetlinkHandler.cpp
NetlinkHandler::NetlinkHandler(int listenerSocket) :NetlinkListener(listenerSocket) {
}int NetlinkHandler::start() {
//startListener由SocketListener实现
return this->
startListener();
}void NetlinkHandler::onEvent(NetlinkEvent *evt) {
VolumeManager *vm =
VolumeManager::Instance();
const char *subsys =
evt->
getSubsystem();
// VolumeManager 调用handleBlockEvent处理事件
if (!strcmp(subsys, "
block"
)) {
vm->
handleBlockEvent(evt);
}
}
NetlinkHandler继承自NetlinkListener,NetlinkListener继承自SocketListener,三者关系如下
文章图片
4.2 startListener
会在父类SocketListener中实现,调用startListener方法
路径:
SocketListener.cpp————————–system/core/libsysutils/src/SocketListener.cpp
SocketListener
int SocketListener::startListener(int backlog) {
......
//创建线程执行函数threadStart
if (pthread_create(&
mThread, NULL, SocketListener::threadStart, this)) {
SLOGE("
pthread_create (%s)"
, strerror(errno));
return -1;
}
return 0;
}
会开启一个线程,那么继续看threadStart方法
void *SocketListener::threadStart(void *obj) {
SocketListener *me =
reinterpret_cast<
SocketListener *>
(obj);
//调用runListener方法
me->
runListener();
pthread_exit(NULL);
return NULL;
}
调用runListener
4.3 runListener
void SocketListener::runListener() {SocketClientCollection pendingList;
......
while (!pendingList.empty()) {it =
pendingList.begin();
SocketClient* c =
*it;
pendingList.erase(it);
//onDataAvailable方法处理有数据发送的socket
if (!onDataAvailable(c)) {
release(c, false);
}
c->
decRef();
}
}
}
会调用onDataAvailable方法, 改方法由子类NetlinkListener和FrameWorkListener实现,所以这里要分两条线4.4和4.5。
4.4 onDataAvailable
由子类FrameWorkListener实现这个方法
bool FrameworkListener::onDataAvailable(SocketClient *c) {
char buffer[CMD_BUF_SIZE];
int len;
//读取socket消息
len =
TEMP_FAILURE_RETRY(read(c->
getSocket(), buffer, sizeof(buffer)));
.....
int i;
for (i =
0;
i <
len;
i+
+
) {
if (buffer[i] =
=
'
\\0'
) {
//根据消息内容 派发命令
dispatchCommand(c, buffer +
offset);
offset =
i +
1;
}
}return true;
}
在onDataAvailable方法里会先读取Socket消息, 然后分发命令
4.4.1 dispatchCommand
void FrameworkListener::dispatchCommand(SocketClient *cli, char *data) {
......
//执行对应的消息
for (i =
mCommands->
begin();
i !=
mCommands->
end();
+
+
i) {
FrameworkCommand *c =
*i;
//匹配命令
if (!strcmp(argv[0], c->
getCommand())) {
//执行命令
if (c->
runCommand(cli, argc, argv)) {
SLOGW("
Handler '
%s'
error (%s)"
, c->
getCommand(), strerror(errno));
}
goto out;
}
}
......
}
会调用FrameworkCommand 的runCommand方法,之前在CommandListener的构造方法里注册的这些指令,就是FrameWorkCommand类型,如下
FrameworkListener.cpp
void FrameworkListener::registerCmd(FrameworkCommand *cmd) {
//添加元素
mCommands->
push_back(cmd);
}
CommandListener.cpp
CommandListener::CommandListener() :FrameworkListener("
vold"
, true) {
//注册多条指令
registerCmd(new DumpCmd());
registerCmd(new VolumeCmd());
registerCmd(new AsecCmd());
registerCmd(new ObbCmd());
registerCmd(new StorageCmd());
registerCmd(new FstrimCmd());
registerCmd(new AppFuseCmd());
}
这里以其中一个指令为VolumeCmd例,会进入到VolumeCmd的runCommand方法
4.4.2 CL.runCommand
CommandListener.cpp
int CommandListener::VolumeCmd::runCommand(SocketClient *cli, int argc, char **argv) {......} else if (cmd =
=
"
mount"
&
&
argc >
2) {
// mount [volId] [flags] [user]
std::string id(argv[2]);
auto vol =
vm->
findVolume(id);
if (vol =
=
nullptr) {
return cli->
sendMsg(ResponseCode::CommandSyntaxError, "
Unknown volume"
, false);
}int mountFlags =
(argc >
3) ? atoi(argv[3]) : 0;
userid_t mountUserId =
(argc >
4) ? atoi(argv[4]) : -1;
vol->
setMountFlags(mountFlags);
vol->
setMountUserId(mountUserId);
//执行真正的挂载操作
int res =
vol->
mount();
if (mountFlags &
android::vold::VolumeBase::MountFlags::kPrimary) {
vm->
setPrimary(vol);
}
//发送应答消息给MountService
return sendGenericOkFail(cli, res);
} else if (cmd =
=
"
unmount"
&
&
argc >
2) {
// unmount [volId]
std::string id(argv[2]);
auto vol =
vm->
findVolume(id);
if (vol =
=
nullptr) {
return cli->
sendMsg(ResponseCode::CommandSyntaxError, "
Unknown volume"
, false);
}return sendGenericOkFail(cli, vol->
unmount());
......
}
}
会根据cmd的不同做相应的处理,在”cmd= mount”操作中,就有
int res =
vol->
mount();
4.4.3 vol-> mount()
vol是VolumeBase的实例,VolumeBase的mount方法由具体的子类EmulatedVolume、PublicVolume、PrivateVolume等实现
执行操作之后会发送应答消息给MountService,这个后续再细讲。
这条线结束了。下面介绍另一条线。回到4.3 runListener,往下走到4.5 onDataAvailable
由子类NetlinkListener实现
4.5 onDataAvailable()
bool NetlinkListener::onDataAvailable(SocketClient *cli)
{
int socket =
cli->
getSocket();
ssize_t count;
uid_t uid =
-1;
......
NetlinkEvent *evt =
new NetlinkEvent();
//解析获得NetlinkEvent实例
if (evt->
decode(mBuffer, count, mFormat)) {
//传入NetlinkEvent实例
onEvent(evt);
}
......
}
NetlinkListener没有实现这个方法, 由子类NetlinkHandler实现
4.5.1 onEvent
void NetlinkHandler::onEvent(NetlinkEvent *evt) {
VolumeManager *vm =
VolumeManager::Instance();
const char *subsys =
evt->
getSubsystem();
if (!subsys) {
SLOGW("
No subsystem found in netlink event"
);
return;
}if (!strcmp(subsys, "
block"
)) {
//调用VolumeManager 的handleBlockEvent方法
vm->
handleBlockEvent(evt);
}
}
获取VolumeManager 单例,调用handleBlockEvent方法
4.5.2 vm-> handleBlockEvent
void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {switch (evt->
getAction()) {
case NetlinkEvent::Action::kAdd: {
for (auto source : mDiskSources) {
if (source->
matches(eventPath)) {
......
auto disk =
new android::vold::Disk(eventPath, device,source->
getNickname(), flags);
//调用disk 的create方法
disk->
create();
mDisks.push_back(std::shared_ptr<
android::vold::Disk>
(disk));
break;
}
}
break;
}
case NetlinkEvent::Action::kChange: {
......
break;
}
case NetlinkEvent::Action::kRemove: {
......
break;
}
......
}
}
根据NetlinkEvent 的不同Action值做相应处理,有add,change,remove三个值。在add里调用了disk-> create()
4.5.3 disk-> create()
路径:
disk.cpp———————–system/vold/disk.cpp
status_t Disk::create() {
CHECK(!mCreated);
mCreated =
true;
//调用notifyEvent方法
notifyEvent(ResponseCode::DiskCreated, StringPrintf("
%d"
, mFlags));
readMetadata();
readPartitions();
return OK;
}
在这一步会调用notifyEvent方法通知SockListener.
void Disk::notifyEvent(int event) {
VolumeManager::Instance()->
getBroadcaster()->
sendBroadcast(event,getId().c_str(), false);
}
到这一步骤, 会发现又回到了3.2 notifyEvent步骤了,之后就跟着3.2继续走了,这里就不重复介绍了.
四、Vold进程总结
关于Vold的整体流程的讲完了,可以跟着我绘制的时序图跟着步骤走,来回多看几次,注意图文结合.
后面会针对
1.由SystemServer进程发起挂载/卸载请求 2.由Kernel发起挂载/卸载请求 这两种情况做更具体的分析,分析源码切记:先整体后局部,不然就没有头绪了,只见树木不见森林.
PS: 水平有限,有不对的地方欢迎一起探讨
推荐阅读
- android-android 带删除功能的EditText
- Android五大布局之一绝对布局(AbsoluteLayout)
- React Native嵌入Android原生应用中
- 腾讯Android面经
- Android五大布局之一表格布局(TableLayout)
- Android:隐藏 EditText 在 Activity 中键盘自动弹出
- Android笔记——判断程序是否第一次启动
- Android Support 包知识
- Android中的AlertDialog使用示例三(单向选择确定对话框)