Android7.0 Vold 進程工作機制分析之由MountService發起掛載請求

Android7.0 Vold 進程工作機制分析之由MountService發起掛載請求

一、MountService發起掛載請求

上一篇Android7.0 Vold 進程工作機制分析之由Kernel發起掛載請求是講解了kernel發起的請求,這一篇接着講由MountService發起掛載請求的流程.

其實這個流程的大部分在上一篇已經被包含了,我還是寫下吧.

1.MountService.mount

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方法執行掛載命令.

2 .NativeDaemonConnector::executeForList()

    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會收到

3. 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消息,然後分發命令

4. FrameWorkListener::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方法

5. CommandListener::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操作

6. vol->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;
}

7. PublicVolume->doMount()

PublicVolume.cpp

status_t PublicVolume::doMount() {
    ......
}

二、小結

MountService發起掛載請求的流程就這麼多,比起由kernel發起請求要簡單些.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章