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/libs/command_util/util.h"
18 
19 #include "sys/time.h"
20 #include "sys/types.h"
21 
22 #include <string>
23 
24 #include "common/libs/fs/shared_buf.h"
25 #include "common/libs/fs/shared_fd.h"
26 #include "common/libs/fs/shared_select.h"
27 #include "common/libs/utils/result.h"
28 #include "host/libs/command_util/runner/defs.h"
29 #include "host/libs/config/cuttlefish_config.h"
30 
31 namespace cuttlefish {
32 namespace {
33 
IsShortAction(const LauncherAction action)34 bool IsShortAction(const LauncherAction action) {
35   switch (action) {
36     case LauncherAction::kFail:
37     case LauncherAction::kPowerwash:
38     case LauncherAction::kRestart:
39     case LauncherAction::kStatus:
40     case LauncherAction::kStop:
41       return true;
42     default:
43       return false;
44   };
45 }
46 
47 template <typename T>
WriteAllBinaryResult(const SharedFD & fd,const T * t)48 static Result<void> WriteAllBinaryResult(const SharedFD& fd, const T* t) {
49   ssize_t n = WriteAllBinary(fd, t);
50   CF_EXPECTF(n > 0, "Write error: {}", fd->StrError());
51   CF_EXPECT(n == sizeof(*t), "Unexpected EOF on write");
52   return {};
53 }
54 
55 template <typename T>
ReadExactBinaryResult(const SharedFD & fd,T * t)56 static Result<void> ReadExactBinaryResult(const SharedFD& fd, T* t) {
57   ssize_t n = ReadExactBinary(fd, t);
58   CF_EXPECTF(n > 0, "Read error: {}", fd->StrError());
59   CF_EXPECT(n == sizeof(*t), "Unexpected EOF on read");
60   return {};
61 }
62 
63 }  // namespace
64 
ReadExitCode(SharedFD monitor_socket)65 Result<RunnerExitCodes> ReadExitCode(SharedFD monitor_socket) {
66   RunnerExitCodes exit_codes;
67   CF_EXPECT(ReadExactBinaryResult(monitor_socket, &exit_codes),
68             "Error reading RunnerExitCodes");
69   return exit_codes;
70 }
71 
GetLauncherMonitorFromInstance(const CuttlefishConfig::InstanceSpecific & instance_config,const int timeout_seconds)72 Result<SharedFD> GetLauncherMonitorFromInstance(
73     const CuttlefishConfig::InstanceSpecific& instance_config,
74     const int timeout_seconds) {
75   std::string monitor_path = instance_config.launcher_monitor_socket_path();
76   CF_EXPECT(!monitor_path.empty(), "No path to launcher monitor found");
77 
78   SharedFD monitor_socket = SharedFD::SocketLocalClient(
79       monitor_path.c_str(), false, SOCK_STREAM, timeout_seconds);
80   CF_EXPECT(monitor_socket->IsOpen(),
81             "Unable to connect to launcher monitor at "
82                 << monitor_path << ":" << monitor_socket->StrError());
83   return monitor_socket;
84 }
85 
GetLauncherMonitor(const CuttlefishConfig & config,const int instance_num,const int timeout_seconds)86 Result<SharedFD> GetLauncherMonitor(const CuttlefishConfig& config,
87                                     const int instance_num,
88                                     const int timeout_seconds) {
89   auto instance_config = config.ForInstance(instance_num);
90   return GetLauncherMonitorFromInstance(instance_config, timeout_seconds);
91 }
92 
ReadLauncherActionFromFd(SharedFD monitor_socket)93 Result<LauncherActionInfo> ReadLauncherActionFromFd(SharedFD monitor_socket) {
94   LauncherAction action;
95   CF_EXPECT(ReadExactBinaryResult(monitor_socket, &action),
96             "Error reading LauncherAction");
97   if (IsShortAction(action)) {
98     return LauncherActionInfo{
99         .action = action,
100         .extended_action = {},
101     };
102   }
103   std::uint32_t length = 0;
104   CF_EXPECT(ReadExactBinaryResult(monitor_socket, &length),
105             "Error reading proto length");
106   if (length == 0) {
107     return LauncherActionInfo{
108         .action = action,
109         .extended_action = {},
110     };
111   }
112   std::string serialized_data(length, 0);
113   ssize_t n =
114       ReadExact(monitor_socket, serialized_data.data(), serialized_data.size());
115   CF_EXPECTF(n > 0, "Read error: {}", monitor_socket->StrError());
116   CF_EXPECT(n == serialized_data.size(), "Unexpected EOF on read");
117 
118   run_cvd::ExtendedLauncherAction extended_action;
119   CF_EXPECT(extended_action.ParseFromString(serialized_data),
120             "Failed to parse ExtendedLauncherAction proto");
121 
122   return LauncherActionInfo{
123       .action = action,
124       .extended_action = std::move(extended_action),
125   };
126 }
127 
WaitForRead(SharedFD monitor_socket,const int timeout_seconds)128 Result<void> WaitForRead(SharedFD monitor_socket, const int timeout_seconds) {
129   // Perform a select with a timeout to guard against launcher hanging
130   SharedFDSet read_set;
131   read_set.Set(monitor_socket);
132   struct timeval timeout = {timeout_seconds, 0};
133   int select_result = Select(&read_set, nullptr, nullptr,
134                              timeout_seconds <= 0 ? nullptr : &timeout);
135   CF_EXPECT(select_result != 0,
136             "Timeout expired waiting for launcher monitor to respond");
137   CF_EXPECT(
138       select_result > 0,
139       "Failed communication with the launcher monitor: " << strerror(errno));
140   return {};
141 }
142 
RunLauncherAction(SharedFD monitor_socket,LauncherAction action,std::optional<int> timeout_seconds)143 Result<void> RunLauncherAction(SharedFD monitor_socket, LauncherAction action,
144                                std::optional<int> timeout_seconds) {
145   CF_EXPECTF(IsShortAction(action),
146              "PerformActionRequest doesn't support extended action \"{}\"",
147              static_cast<const char>(action));
148   CF_EXPECT(WriteAllBinaryResult(monitor_socket, &action),
149             "Error writing LauncherAction");
150 
151   if (timeout_seconds.has_value()) {
152     CF_EXPECT(WaitForRead(monitor_socket, timeout_seconds.value()));
153   }
154   LauncherResponse response;
155   CF_EXPECT(ReadExactBinaryResult(monitor_socket, &response),
156             "Error reading LauncherResponse");
157   CF_EXPECT_EQ((int)response, (int)LauncherResponse::kSuccess);
158   return {};
159 }
160 
RunLauncherAction(SharedFD monitor_socket,const run_cvd::ExtendedLauncherAction & extended_action,std::optional<int> timeout_seconds)161 Result<void> RunLauncherAction(
162     SharedFD monitor_socket,
163     const run_cvd::ExtendedLauncherAction& extended_action,
164     std::optional<int> timeout_seconds) {
165   const std::string serialized_data = extended_action.SerializeAsString();
166   CF_EXPECT(!serialized_data.empty(), "failed to serialize proto");
167 
168   const LauncherAction action = LauncherAction::kExtended;
169   CF_EXPECT(WriteAllBinaryResult(monitor_socket, &action),
170             "Error writing LauncherAction");
171   const std::uint32_t length = serialized_data.size();
172   CF_EXPECT(WriteAllBinaryResult(monitor_socket, &length),
173             "Error writing proto length");
174   if (!serialized_data.empty()) {
175     ssize_t n = WriteAll(monitor_socket, serialized_data.data(),
176                          serialized_data.size());
177     CF_EXPECTF(n > 0, "Write error: {}", monitor_socket->StrError());
178     CF_EXPECT(n == serialized_data.size(), "Unexpected EOF on write");
179   }
180 
181   if (timeout_seconds.has_value()) {
182     CF_EXPECT(WaitForRead(monitor_socket, timeout_seconds.value()));
183   }
184   LauncherResponse response;
185   CF_EXPECT(ReadExactBinaryResult(monitor_socket, &response),
186             "Error reading LauncherResponse");
187   CF_EXPECT_EQ((int)response, (int)LauncherResponse::kSuccess);
188   return {};
189 }
190 
191 }  // namespace cuttlefish
192