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