• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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/fleet.h"
18 
19 #include <sys/types.h>
20 
21 #include <mutex>
22 
23 #include <android-base/file.h>
24 
25 #include "common/libs/fs/shared_buf.h"
26 #include "common/libs/fs/shared_fd.h"
27 #include "common/libs/utils/contains.h"
28 #include "common/libs/utils/files.h"
29 #include "common/libs/utils/result.h"
30 #include "host/commands/cvd/server_command/server_handler.h"
31 #include "host/commands/cvd/server_command/utils.h"
32 #include "host/commands/cvd/types.h"
33 #include "host/libs/config/cuttlefish_config.h"
34 
35 namespace cuttlefish {
36 
37 class CvdFleetCommandHandler : public CvdServerHandler {
38  public:
INJECT(CvdFleetCommandHandler (InstanceManager & instance_manager,SubprocessWaiter & subprocess_waiter))39   INJECT(CvdFleetCommandHandler(InstanceManager& instance_manager,
40                                 SubprocessWaiter& subprocess_waiter))
41       : instance_manager_(instance_manager),
42         subprocess_waiter_(subprocess_waiter) {}
43 
44   Result<bool> CanHandle(const RequestWithStdio& request) const;
45   Result<cvd::Response> Handle(const RequestWithStdio& request) override;
46   Result<void> Interrupt() override;
CmdList() const47   cvd_common::Args CmdList() const override { return {kFleetSubcmd}; }
48 
49  private:
50   InstanceManager& instance_manager_;
51   SubprocessWaiter& subprocess_waiter_;
52   std::mutex interruptible_;
53   bool interrupted_ = false;
54 
55   static constexpr char kFleetSubcmd[] = "fleet";
56   Result<cvd::Status> HandleCvdFleet(const uid_t uid, const SharedFD& out,
57                                      const SharedFD& err,
58                                      const cvd_common::Args& cmd_args) const;
59   Result<cvd::Status> CvdFleetHelp(const SharedFD& out) const;
60   bool IsHelp(const cvd_common::Args& cmd_args) const;
61 };
62 
CanHandle(const RequestWithStdio & request) const63 Result<bool> CvdFleetCommandHandler::CanHandle(
64     const RequestWithStdio& request) const {
65   auto invocation = ParseInvocation(request.Message());
66   return invocation.command == kFleetSubcmd;
67 }
68 
Interrupt()69 Result<void> CvdFleetCommandHandler::Interrupt() {
70   std::scoped_lock interrupt_lock(interruptible_);
71   interrupted_ = true;
72   CF_EXPECT(subprocess_waiter_.Interrupt());
73   return {};
74 }
75 
Handle(const RequestWithStdio & request)76 Result<cvd::Response> CvdFleetCommandHandler::Handle(
77     const RequestWithStdio& request) {
78   std::unique_lock interrupt_lock(interruptible_);
79   if (interrupted_) {
80     return CF_ERR("Interrupted");
81   }
82   CF_EXPECT(CanHandle(request));
83   CF_EXPECT(request.Credentials() != std::nullopt);
84   const uid_t uid = request.Credentials()->uid;
85 
86   cvd::Response response;
87   response.mutable_command_response();
88 
89   auto [sub_cmd, args] = ParseInvocation(request.Message());
90   auto envs =
91       cvd_common::ConvertToEnvs(request.Message().command_request().env());
92   if (!IsHelp(args)) {
93     CF_EXPECT(Contains(envs, "ANDROID_HOST_OUT") &&
94               DirectoryExists(envs.at("ANDROID_HOST_OUT")));
95   }
96 
97   *response.mutable_status() =
98       CF_EXPECT(HandleCvdFleet(uid, request.Out(), request.Err(), args));
99 
100   return response;
101 }
102 
HandleCvdFleet(const uid_t uid,const SharedFD & out,const SharedFD & err,const cvd_common::Args & cmd_args) const103 Result<cvd::Status> CvdFleetCommandHandler::HandleCvdFleet(
104     const uid_t uid, const SharedFD& out, const SharedFD& err,
105     const cvd_common::Args& cmd_args) const {
106   if (IsHelp(cmd_args)) {
107     auto status = CF_EXPECT(CvdFleetHelp(out));
108     return status;
109   }
110   auto status = CF_EXPECT(instance_manager_.CvdFleet(uid, out, err, cmd_args));
111   return status;
112 }
113 
IsHelp(const cvd_common::Args & args) const114 bool CvdFleetCommandHandler::IsHelp(const cvd_common::Args& args) const {
115   for (const auto& arg : args) {
116     if (arg == "--help" || arg == "-help") {
117       return true;
118     }
119   }
120   return false;
121 }
122 
CvdFleetHelp(const SharedFD & out) const123 Result<cvd::Status> CvdFleetCommandHandler::CvdFleetHelp(
124     const SharedFD& out) const {
125   WriteAll(out, "Simply run \"cvd fleet\" as it has no other flags.\n");
126   WriteAll(out, "\n");
127   WriteAll(out, "\"cvd fleet\" will:\n");
128   WriteAll(out,
129            "      1. tell whether the devices (i.e. \"run_cvd\" processes) are "
130            "active.\n");
131   WriteAll(out,
132            "      2. optionally list the active devices with information.\n");
133   cvd::Status status;
134   status.set_code(cvd::Status::OK);
135   return status;
136 }
137 
138 fruit::Component<fruit::Required<InstanceManager, SubprocessWaiter>>
cvdFleetCommandComponent()139 cvdFleetCommandComponent() {
140   return fruit::createComponent()
141       .addMultibinding<CvdServerHandler, CvdFleetCommandHandler>();
142 }
143 
144 }  // namespace cuttlefish
145