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