上一篇Android7.0 Vold 進程工做機制分析之由Kernel發起掛載請求是講解了kernel發起的請求,這一篇接着講由MountService發起掛載請求的流程. android
其實這個流程的大部分在上一篇已經被包含了,我仍是寫下吧.socket
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方法執行掛載命令.ide
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會收到spa
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消息,而後分發命令.net
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類型,以下code
FrameworkListener.cppblog
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方法get
CommandListener.cppcmd
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發起請求要簡單些.