• 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/handler_proxy.h"
18 
19 #include <mutex>
20 #include <vector>
21 
22 #include <android-base/strings.h>
23 
24 #include "host/commands/cvd/common_utils.h"
25 #include "host/commands/cvd/frontline_parser.h"
26 #include "host/commands/cvd/selector/selector_constants.h"
27 #include "host/commands/cvd/server_command/server_handler.h"
28 #include "host/commands/cvd/server_command/utils.h"
29 #include "host/commands/cvd/types.h"
30 
31 namespace cuttlefish {
32 
33 class CvdServerHandlerProxy : public CvdServerHandler {
34  public:
INJECT(CvdServerHandlerProxy (CommandSequenceExecutor & executor))35   INJECT(CvdServerHandlerProxy(CommandSequenceExecutor& executor))
36       : executor_(executor) {}
37 
CanHandle(const RequestWithStdio & request) const38   Result<bool> CanHandle(const RequestWithStdio& request) const override {
39     auto invocation = ParseInvocation(request.Message());
40     return (invocation.command == "process");
41   }
42 
43   // the input format is:
44   //   cmd_args:      cvd cmdline-parser
45   //   selector_args: [command args to parse]
Handle(const RequestWithStdio & request)46   Result<cvd::Response> Handle(const RequestWithStdio& request) override {
47     std::unique_lock interrupt_lock(interruptible_);
48     CF_EXPECT(!interrupted_, "Interrupted");
49     CF_EXPECT(CanHandle(request));
50 
51     const auto& selector_opts =
52         request.Message().command_request().selector_opts();
53     auto all_args = cvd_common::ConvertToArgs(selector_opts.args());
54     CF_EXPECT_GE(all_args.size(), 1);
55     if (all_args.size() == 1) {
56       CF_EXPECT_EQ(all_args.front(), "cvd");
57       all_args = cvd_common::Args{"cvd", "help"};
58     }
59 
60     cvd_common::Envs envs =
61         cvd_common::ConvertToEnvs(request.Message().command_request().env());
62 
63     auto subcmds = executor_.CmdList();
64     auto selector_flag_collection =
65         selector::SelectorFlags::New().FlagsAsCollection();
66 
67     FrontlineParser::ParserParam server_param{
68         .server_supported_subcmds = subcmds,
69         .internal_cmds = std::vector<std::string>{},
70         .all_args = all_args,
71         .cvd_flags = std::move(selector_flag_collection)};
72     auto frontline_parser = CF_EXPECT(FrontlineParser::Parse(server_param));
73     CF_EXPECT(frontline_parser != nullptr);
74 
75     const auto prog_path = frontline_parser->ProgPath();
76     const auto new_sub_cmd = frontline_parser->SubCmd();
77     cvd_common::Args cmd_args{frontline_parser->SubCmdArgs()};
78     cvd_common::Args selector_args{frontline_parser->CvdArgs()};
79 
80     cvd_common::Args new_exec_args{prog_path};
81     if (new_sub_cmd) {
82       new_exec_args.push_back(*new_sub_cmd);
83     }
84     new_exec_args.insert(new_exec_args.end(), cmd_args.begin(), cmd_args.end());
85 
86     cvd::Request exec_request = MakeRequest(
87         {.cmd_args = new_exec_args,
88          .env = envs,
89          .selector_args = selector_args,
90          .working_dir =
91              request.Message().command_request().working_directory()},
92         request.Message().command_request().wait_behavior());
93 
94     RequestWithStdio forwarded_request(
95         request.Client(), std::move(exec_request), request.FileDescriptors(),
96         request.Credentials());
97     interrupt_lock.unlock();
98     SharedFD dev_null = SharedFD::Open("/dev/null", O_RDWR);
99     CF_EXPECT(dev_null->IsOpen(), "Failed to open /dev/null");
100     const auto responses =
101         CF_EXPECT(executor_.Execute({std::move(forwarded_request)}, dev_null));
102     CF_EXPECT_EQ(responses.size(), 1);
103     return responses.front();
104   }
105 
Interrupt()106   Result<void> Interrupt() override {
107     std::scoped_lock interrupt_lock(interruptible_);
108     interrupted_ = true;
109     CF_EXPECT(executor_.Interrupt());
110     return {};
111   }
112 
113   // not intended to be used by the user
CmdList() const114   cvd_common::Args CmdList() const override { return {}; }
115 
116  private:
117   std::mutex interruptible_;
118   bool interrupted_ = false;
119   CommandSequenceExecutor& executor_;
120 };
121 
122 fruit::Component<fruit::Required<CommandSequenceExecutor>>
CvdHandlerProxyComponent()123 CvdHandlerProxyComponent() {
124   return fruit::createComponent()
125       .addMultibinding<CvdServerHandler, CvdServerHandlerProxy>();
126 }
127 
128 }  // namespace cuttlefish
129