159 lines
6.1 KiB
C++
159 lines
6.1 KiB
C++
|
|
/*
|
||
|
|
* Copyright (C) 2023 The Android Open Source Project
|
||
|
|
*
|
||
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
|
* you may not use this file except in compliance with the License.
|
||
|
|
* You may obtain a copy of the License at
|
||
|
|
*
|
||
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
|
*
|
||
|
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
|
* See the License for the specific language governing permissions and
|
||
|
|
* limitations under the License.
|
||
|
|
*/
|
||
|
|
|
||
|
|
#include "host/commands/cvd/server_command/crosvm.h"
|
||
|
|
|
||
|
|
#include <android-base/strings.h>
|
||
|
|
|
||
|
|
#include <iostream>
|
||
|
|
#include <mutex>
|
||
|
|
#include <optional>
|
||
|
|
#include <sstream>
|
||
|
|
#include <string>
|
||
|
|
#include <vector>
|
||
|
|
|
||
|
|
#include "common/libs/fs/shared_buf.h"
|
||
|
|
#include "common/libs/utils/contains.h"
|
||
|
|
#include "common/libs/utils/subprocess.h"
|
||
|
|
#include "host/commands/cvd/flag.h"
|
||
|
|
#include "host/commands/cvd/selector/instance_group_record.h"
|
||
|
|
#include "host/commands/cvd/selector/instance_record.h"
|
||
|
|
#include "host/commands/cvd/selector/selector_constants.h"
|
||
|
|
#include "host/commands/cvd/server_command/server_handler.h"
|
||
|
|
#include "host/commands/cvd/server_command/utils.h"
|
||
|
|
#include "host/commands/cvd/types.h"
|
||
|
|
|
||
|
|
namespace cuttlefish {
|
||
|
|
|
||
|
|
class CvdCrosVmCommandHandler : public CvdServerHandler {
|
||
|
|
public:
|
||
|
|
INJECT(CvdCrosVmCommandHandler(InstanceManager& instance_manager,
|
||
|
|
SubprocessWaiter& subprocess_waiter))
|
||
|
|
: instance_manager_{instance_manager},
|
||
|
|
subprocess_waiter_(subprocess_waiter),
|
||
|
|
crosvm_operations_{"suspend", "resume", "snapshot"} {}
|
||
|
|
|
||
|
|
Result<bool> CanHandle(const RequestWithStdio& request) const {
|
||
|
|
auto invocation = ParseInvocation(request.Message());
|
||
|
|
return Contains(crosvm_operations_, invocation.command);
|
||
|
|
}
|
||
|
|
|
||
|
|
Result<cvd::Response> Handle(const RequestWithStdio& request) override {
|
||
|
|
std::unique_lock interrupt_lock(interruptible_);
|
||
|
|
CF_EXPECT(!interrupted_, "Interrupted");
|
||
|
|
CF_EXPECT(CanHandle(request));
|
||
|
|
CF_EXPECT(VerifyPrecondition(request));
|
||
|
|
const uid_t uid = request.Credentials()->uid;
|
||
|
|
cvd_common::Envs envs =
|
||
|
|
cvd_common::ConvertToEnvs(request.Message().command_request().env());
|
||
|
|
|
||
|
|
auto [crosvm_op, subcmd_args] = ParseInvocation(request.Message());
|
||
|
|
/*
|
||
|
|
* crosvm suspend/resume/snapshot support --help only. Not --helpxml, etc.
|
||
|
|
*
|
||
|
|
* Otherwise, IsHelpSubcmd() should be used here instead.
|
||
|
|
*/
|
||
|
|
auto help_flag = CvdFlag("help", false);
|
||
|
|
cvd_common::Args subcmd_args_copy{subcmd_args};
|
||
|
|
auto help_parse_result = help_flag.CalculateFlag(subcmd_args_copy);
|
||
|
|
bool is_help = help_parse_result.ok() && (*help_parse_result);
|
||
|
|
|
||
|
|
Command command =
|
||
|
|
is_help ? CF_EXPECT(HelpCommand(request, crosvm_op, subcmd_args, envs))
|
||
|
|
: CF_EXPECT(NonHelpCommand(request, uid, crosvm_op, subcmd_args,
|
||
|
|
envs));
|
||
|
|
SubprocessOptions options;
|
||
|
|
CF_EXPECT(subprocess_waiter_.Setup(command.Start(options)));
|
||
|
|
interrupt_lock.unlock();
|
||
|
|
|
||
|
|
auto infop = CF_EXPECT(subprocess_waiter_.Wait());
|
||
|
|
return ResponseFromSiginfo(infop);
|
||
|
|
}
|
||
|
|
|
||
|
|
Result<void> Interrupt() override {
|
||
|
|
std::scoped_lock interrupt_lock(interruptible_);
|
||
|
|
interrupted_ = true;
|
||
|
|
CF_EXPECT(subprocess_waiter_.Interrupt());
|
||
|
|
return {};
|
||
|
|
}
|
||
|
|
cvd_common::Args CmdList() const override {
|
||
|
|
return cvd_common::Args(crosvm_operations_.begin(),
|
||
|
|
crosvm_operations_.end());
|
||
|
|
}
|
||
|
|
|
||
|
|
private:
|
||
|
|
Result<Command> HelpCommand(const RequestWithStdio& request,
|
||
|
|
const std::string& crosvm_op,
|
||
|
|
const cvd_common::Args& subcmd_args,
|
||
|
|
cvd_common::Envs envs) {
|
||
|
|
CF_EXPECT(Contains(envs, kAndroidHostOut));
|
||
|
|
cvd_common::Args crosvm_args{crosvm_op};
|
||
|
|
crosvm_args.insert(crosvm_args.end(), subcmd_args.begin(),
|
||
|
|
subcmd_args.end());
|
||
|
|
return CF_EXPECT(
|
||
|
|
ConstructCvdHelpCommand("crosvm", envs, crosvm_args, request));
|
||
|
|
}
|
||
|
|
|
||
|
|
Result<Command> NonHelpCommand(const RequestWithStdio& request,
|
||
|
|
const uid_t uid, const std::string& crosvm_op,
|
||
|
|
const cvd_common::Args& subcmd_args,
|
||
|
|
const cvd_common::Envs& envs) {
|
||
|
|
const auto& selector_opts =
|
||
|
|
request.Message().command_request().selector_opts();
|
||
|
|
const auto selector_args = cvd_common::ConvertToArgs(selector_opts.args());
|
||
|
|
|
||
|
|
auto instance =
|
||
|
|
CF_EXPECT(instance_manager_.SelectInstance(selector_args, envs, uid));
|
||
|
|
const auto& instance_group = instance.ParentGroup();
|
||
|
|
const auto instance_id = instance.InstanceId();
|
||
|
|
auto home = instance_group.HomeDir();
|
||
|
|
const auto socket_file_path =
|
||
|
|
ConcatToString(home, "/cuttlefish_runtime.", instance_id,
|
||
|
|
"/internal/"
|
||
|
|
"crosvm_control.sock");
|
||
|
|
|
||
|
|
auto android_host_out = instance_group.HostArtifactsPath();
|
||
|
|
auto crosvm_bin_path = ConcatToString(android_host_out, "/bin/crosvm");
|
||
|
|
|
||
|
|
cvd_common::Args crosvm_args{crosvm_op};
|
||
|
|
crosvm_args.insert(crosvm_args.end(), subcmd_args.begin(),
|
||
|
|
subcmd_args.end());
|
||
|
|
crosvm_args.push_back(socket_file_path);
|
||
|
|
return CF_EXPECT(
|
||
|
|
ConstructCvdGenericNonHelpCommand({.bin_file = "crosvm",
|
||
|
|
.envs = envs,
|
||
|
|
.cmd_args = std::move(crosvm_args),
|
||
|
|
.android_host_out = android_host_out,
|
||
|
|
.home = home,
|
||
|
|
.verbose = true},
|
||
|
|
request));
|
||
|
|
}
|
||
|
|
|
||
|
|
InstanceManager& instance_manager_;
|
||
|
|
SubprocessWaiter& subprocess_waiter_;
|
||
|
|
std::mutex interruptible_;
|
||
|
|
bool interrupted_ = false;
|
||
|
|
std::vector<std::string> crosvm_operations_;
|
||
|
|
};
|
||
|
|
|
||
|
|
fruit::Component<fruit::Required<InstanceManager, SubprocessWaiter>>
|
||
|
|
CvdCrosVmComponent() {
|
||
|
|
return fruit::createComponent()
|
||
|
|
.addMultibinding<CvdServerHandler, CvdCrosVmCommandHandler>();
|
||
|
|
}
|
||
|
|
|
||
|
|
} // namespace cuttlefish
|