/* * 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/env.h" #include #include #include #include #include #include #include #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 CvdEnvCommandHandler : public CvdServerHandler { public: INJECT(CvdEnvCommandHandler(InstanceManager& instance_manager, SubprocessWaiter& subprocess_waiter)) : instance_manager_{instance_manager}, subprocess_waiter_(subprocess_waiter), cvd_env_operations_{"env"} {} Result CanHandle(const RequestWithStdio& request) const { auto invocation = ParseInvocation(request.Message()); return Contains(cvd_env_operations_, invocation.command); } Result 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 [_, subcmd_args] = ParseInvocation(request.Message()); /* * cvd_env --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, subcmd_args, envs)) : CF_EXPECT(NonHelpCommand(request, uid, 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 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(cvd_env_operations_.begin(), cvd_env_operations_.end()); } private: Result HelpCommand(const RequestWithStdio& request, const cvd_common::Args& subcmd_args, const cvd_common::Envs& envs) { CF_EXPECT(Contains(envs, kAndroidHostOut)); return CF_EXPECT( ConstructCvdHelpCommand(kCvdEnvBin, envs, subcmd_args, request)); } Result NonHelpCommand(const RequestWithStdio& request, const uid_t uid, 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& home = instance_group.HomeDir(); const auto& android_host_out = instance_group.HostArtifactsPath(); auto cvd_env_bin_path = ConcatToString(android_host_out, "/bin/", kCvdEnvBin); const auto& internal_device_name = instance.InternalDeviceName(); cvd_common::Args cvd_env_args{internal_device_name}; cvd_env_args.insert(cvd_env_args.end(), subcmd_args.begin(), subcmd_args.end()); return CF_EXPECT( ConstructCvdGenericNonHelpCommand({.bin_file = kCvdEnvBin, .envs = envs, .cmd_args = cvd_env_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 cvd_env_operations_; static constexpr char kCvdEnvBin[] = "cvd_internal_env"; }; fruit::Component> CvdEnvComponent() { return fruit::createComponent() .addMultibinding(); } } // namespace cuttlefish