• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "host/commands/cvd/server_command/env.h"
18 
19 #include <android-base/strings.h>
20 
21 #include <iostream>
22 #include <mutex>
23 #include <optional>
24 #include <sstream>
25 #include <string>
26 #include <vector>
27 
28 #include "common/libs/fs/shared_buf.h"
29 #include "common/libs/utils/contains.h"
30 #include "common/libs/utils/subprocess.h"
31 #include "host/commands/cvd/flag.h"
32 #include "host/commands/cvd/selector/instance_group_record.h"
33 #include "host/commands/cvd/selector/instance_record.h"
34 #include "host/commands/cvd/selector/selector_constants.h"
35 #include "host/commands/cvd/server_command/server_handler.h"
36 #include "host/commands/cvd/server_command/utils.h"
37 #include "host/commands/cvd/types.h"
38 
39 namespace cuttlefish {
40 
41 class CvdEnvCommandHandler : public CvdServerHandler {
42  public:
INJECT(CvdEnvCommandHandler (InstanceManager & instance_manager,SubprocessWaiter & subprocess_waiter))43   INJECT(CvdEnvCommandHandler(InstanceManager& instance_manager,
44                               SubprocessWaiter& subprocess_waiter))
45       : instance_manager_{instance_manager},
46         subprocess_waiter_(subprocess_waiter),
47         cvd_env_operations_{"env"} {}
48 
CanHandle(const RequestWithStdio & request) const49   Result<bool> CanHandle(const RequestWithStdio& request) const {
50     auto invocation = ParseInvocation(request.Message());
51     return Contains(cvd_env_operations_, invocation.command);
52   }
53 
Handle(const RequestWithStdio & request)54   Result<cvd::Response> Handle(const RequestWithStdio& request) override {
55     std::unique_lock interrupt_lock(interruptible_);
56     CF_EXPECT(!interrupted_, "Interrupted");
57     CF_EXPECT(CanHandle(request));
58     CF_EXPECT(VerifyPrecondition(request));
59     const uid_t uid = request.Credentials()->uid;
60     cvd_common::Envs envs =
61         cvd_common::ConvertToEnvs(request.Message().command_request().env());
62 
63     auto [_, subcmd_args] = ParseInvocation(request.Message());
64 
65     /*
66      * cvd_env --help only. Not --helpxml, etc.
67      *
68      * Otherwise, IsHelpSubcmd() should be used here instead.
69      */
70     auto help_flag = CvdFlag("help", false);
71     cvd_common::Args subcmd_args_copy{subcmd_args};
72     auto help_parse_result = help_flag.CalculateFlag(subcmd_args_copy);
73     bool is_help = help_parse_result.ok() && (*help_parse_result);
74 
75     Command command =
76         is_help ? CF_EXPECT(HelpCommand(request, subcmd_args, envs))
77                 : CF_EXPECT(NonHelpCommand(request, uid, subcmd_args, envs));
78     SubprocessOptions options;
79     CF_EXPECT(subprocess_waiter_.Setup(command.Start(options)));
80     interrupt_lock.unlock();
81 
82     auto infop = CF_EXPECT(subprocess_waiter_.Wait());
83     return ResponseFromSiginfo(infop);
84   }
85 
Interrupt()86   Result<void> Interrupt() override {
87     std::scoped_lock interrupt_lock(interruptible_);
88     interrupted_ = true;
89     CF_EXPECT(subprocess_waiter_.Interrupt());
90     return {};
91   }
92 
CmdList() const93   cvd_common::Args CmdList() const override {
94     return cvd_common::Args(cvd_env_operations_.begin(),
95                             cvd_env_operations_.end());
96   }
97 
98  private:
HelpCommand(const RequestWithStdio & request,const cvd_common::Args & subcmd_args,const cvd_common::Envs & envs)99   Result<Command> HelpCommand(const RequestWithStdio& request,
100                               const cvd_common::Args& subcmd_args,
101                               const cvd_common::Envs& envs) {
102     CF_EXPECT(Contains(envs, kAndroidHostOut));
103     return CF_EXPECT(
104         ConstructCvdHelpCommand(kCvdEnvBin, envs, subcmd_args, request));
105   }
106 
NonHelpCommand(const RequestWithStdio & request,const uid_t uid,const cvd_common::Args & subcmd_args,const cvd_common::Envs & envs)107   Result<Command> NonHelpCommand(const RequestWithStdio& request,
108                                  const uid_t uid,
109                                  const cvd_common::Args& subcmd_args,
110                                  const cvd_common::Envs& envs) {
111     const auto& selector_opts =
112         request.Message().command_request().selector_opts();
113     const auto selector_args = cvd_common::ConvertToArgs(selector_opts.args());
114 
115     auto instance =
116         CF_EXPECT(instance_manager_.SelectInstance(selector_args, envs, uid));
117     const auto& instance_group = instance.ParentGroup();
118     const auto& home = instance_group.HomeDir();
119 
120     const auto& android_host_out = instance_group.HostArtifactsPath();
121     auto cvd_env_bin_path =
122         ConcatToString(android_host_out, "/bin/", kCvdEnvBin);
123     const auto& internal_device_name = instance.InternalDeviceName();
124 
125     cvd_common::Args cvd_env_args{internal_device_name};
126     cvd_env_args.insert(cvd_env_args.end(), subcmd_args.begin(),
127                         subcmd_args.end());
128 
129     return CF_EXPECT(
130         ConstructCvdGenericNonHelpCommand({.bin_file = kCvdEnvBin,
131                                            .envs = envs,
132                                            .cmd_args = cvd_env_args,
133                                            .android_host_out = android_host_out,
134                                            .home = home,
135                                            .verbose = true},
136                                           request));
137   }
138 
139   InstanceManager& instance_manager_;
140   SubprocessWaiter& subprocess_waiter_;
141   std::mutex interruptible_;
142   bool interrupted_ = false;
143   std::vector<std::string> cvd_env_operations_;
144 
145   static constexpr char kCvdEnvBin[] = "cvd_internal_env";
146 };
147 
148 fruit::Component<fruit::Required<InstanceManager, SubprocessWaiter>>
CvdEnvComponent()149 CvdEnvComponent() {
150   return fruit::createComponent()
151       .addMultibinding<CvdServerHandler, CvdEnvCommandHandler>();
152 }
153 
154 }  // namespace cuttlefish
155