上一篇Android7.0 Vold 进程工作机制分析之由Kernel发起挂载请求是讲解了kernel发起的请求,这一篇接着讲由MountService发起挂载请求的流程.
其实这个流程的大部分在上一篇已经被包含了,我还是写下吧.
class MountService extends IMountService.Stub implements INativeDaemonConnectorCallbacks, Watchdog.Monitor {
@Override
public void mount(String volId) {
......
try {
mConnector.execute("volume", "mount", vol.id, vol.mountFlags, vol.mountUserId);
} catch (NativeDaemonConnectorException e) {
throw e.rethrowAsParcelableException();
}
}
......
}
MountService调用mount方法,在方法内部调用NativeDaemonConnector的execute方法执行挂载命令.
final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdog.Monitor {
......
public NativeDaemonEvent[] executeForList(long timeoutMs, String cmd, Object... args)
throws NativeDaemonConnectorException {
......
synchronized (mDaemonLock) {
if (mOutputStream == null) {
throw new NativeDaemonConnectorException("missing output stream");
} else {
try {
//往Socket 输出流写入命令
mOutputStream.write(rawCmd.getBytes(StandardCharsets.UTF_8));
} catch (IOException e) {
throw new NativeDaemonConnectorException("problem sending command", e);
}
}
......
}
往Socket写入输出流之后,Vold中FrameWorkListener的onDataAvailable会收到
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消息,然后分发命令
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方法
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);
......
}
}
会执行实际的mount操作
vol是VolumeBase的实例,VolumeBase的mount方法由具体的子类EmulatedVolume、PublicVolume、PrivateVolume等实现
执行操作之后会发送应答消息给MountService.
status_t VolumeBase::mount() {
......
setState(State::kChecking);
//doMount由子类实现实际挂载操作
status_t res = doMount();
if (res == OK) {
setState(State::kMounted);
} else {
setState(State::kUnmountable);
}
return res;
}
PublicVolume.cpp
status_t PublicVolume::doMount() {
......
}
MountService发起挂载请求的流程就这么多,比起由kernel发起请求要简单些.