1 //
2 // Copyright (C) 2019 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 #include "host/commands/run_cvd/launch/launch.h"
17
18 #include <sstream>
19 #include <string>
20 #include <unordered_set>
21 #include <utility>
22 #include <vector>
23
24 #include <android-base/logging.h>
25 #include <fmt/ranges.h>
26 #include <fruit/fruit.h>
27
28 #include "common/libs/fs/shared_fd.h"
29 #include "common/libs/utils/result.h"
30 #include "host/commands/run_cvd/reporting.h"
31 #include "host/libs/config/command_source.h"
32 #include "host/libs/config/cuttlefish_config.h"
33 #include "host/libs/config/known_paths.h"
34
35 namespace cuttlefish {
36
37 namespace {
38
CreateUnixInputServer(const std::string & path)39 SharedFD CreateUnixInputServer(const std::string& path) {
40 auto server =
41 SharedFD::SocketLocalServer(path.c_str(), false, SOCK_STREAM, 0666);
42 if (!server->IsOpen()) {
43 LOG(ERROR) << "Unable to create unix input server: " << server->StrError();
44 return {};
45 }
46 return server;
47 }
48
LaunchCustomActionServers(Command & webrtc_cmd,const std::vector<CustomActionServerConfig> & custom_actions)49 std::vector<Command> LaunchCustomActionServers(
50 Command& webrtc_cmd,
51 const std::vector<CustomActionServerConfig>& custom_actions) {
52 bool first = true;
53 std::vector<Command> commands;
54 for (const auto& custom_action : custom_actions) {
55 // Create a socket pair that will be used for communication between
56 // WebRTC and the action server.
57 SharedFD webrtc_socket, action_server_socket;
58 if (!SharedFD::SocketPair(AF_LOCAL, SOCK_STREAM, 0, &webrtc_socket,
59 &action_server_socket)) {
60 LOG(ERROR) << "Unable to create custom action server socket pair: "
61 << strerror(errno);
62 continue;
63 }
64
65 // Launch the action server, providing its socket pair fd as the only
66 // argument.
67 auto binary = HostBinaryPath(custom_action.server);
68 Command command(binary);
69 command.AddParameter(action_server_socket);
70 commands.emplace_back(std::move(command));
71
72 // Pass the WebRTC socket pair fd to WebRTC.
73 if (first) {
74 first = false;
75 webrtc_cmd.AddParameter("-action_servers=", custom_action.server, ":",
76 webrtc_socket);
77 } else {
78 webrtc_cmd.AppendToLastParameter(",", custom_action.server, ":",
79 webrtc_socket);
80 }
81 }
82 return commands;
83 }
84
85 // Creates the frame and input sockets and add the relevant arguments to
86 // webrtc commands
87 class StreamerSockets : public virtual SetupFeature {
88 public:
INJECT(StreamerSockets (const CuttlefishConfig & config,InputConnectionsProvider & input_connections_provider,const CuttlefishConfig::InstanceSpecific & instance))89 INJECT(StreamerSockets(const CuttlefishConfig& config,
90 InputConnectionsProvider& input_connections_provider,
91 const CuttlefishConfig::InstanceSpecific& instance))
92 : config_(config),
93 instance_(instance),
94 input_connections_provider_(input_connections_provider) {}
95
AppendCommandArguments(Command & cmd)96 void AppendCommandArguments(Command& cmd) {
97 const int touch_count = instance_.display_configs().size() +
98 instance_.touchpad_configs().size();
99 if (touch_count > 0) {
100 if (instance_.guest_os() ==
101 CuttlefishConfig::InstanceSpecific::GuestOs::ChromeOs) {
102 cmd.AddParameter("--multitouch=false");
103 }
104 std::vector<SharedFD> touch_connections =
105 input_connections_provider_.TouchscreenConnections();
106 for (const SharedFD& touchpad_connection :
107 input_connections_provider_.TouchpadConnections()) {
108 touch_connections.push_back(touchpad_connection);
109 }
110 cmd.AddParameter("-touch_fds=", touch_connections[0]);
111 for (int i = 1; i < touch_connections.size(); ++i) {
112 cmd.AppendToLastParameter(",", touch_connections[i]);
113 }
114 }
115 if (instance_.enable_mouse()) {
116 cmd.AddParameter("-mouse_fd=",
117 input_connections_provider_.MouseConnection());
118 }
119 cmd.AddParameter("-rotary_fd=",
120 input_connections_provider_.RotaryDeviceConnection());
121 cmd.AddParameter("-keyboard_fd=",
122 input_connections_provider_.KeyboardConnection());
123 cmd.AddParameter("-frame_server_fd=", frames_server_);
124 if (instance_.enable_audio()) {
125 cmd.AddParameter("--audio_server_fd=", audio_server_);
126 }
127 cmd.AddParameter("--confui_in_fd=", confui_in_fd_);
128 cmd.AddParameter("--confui_out_fd=", confui_out_fd_);
129 cmd.AddParameter("-switches_fd=",
130 input_connections_provider_.SwitchesConnection());
131 }
132
133 // SetupFeature
Name() const134 std::string Name() const override { return "StreamerSockets"; }
Enabled() const135 bool Enabled() const override {
136 bool is_qemu = config_.vm_manager() == VmmMode::kQemu;
137 bool is_accelerated = instance_.gpu_mode() != kGpuModeGuestSwiftshader;
138 return !(is_qemu && is_accelerated);
139 }
140
141 private:
Dependencies() const142 std::unordered_set<SetupFeature*> Dependencies() const override {
143 return {&input_connections_provider_};
144 }
145
ResultSetup()146 Result<void> ResultSetup() override {
147 frames_server_ = CreateUnixInputServer(instance_.frames_socket_path());
148 CF_EXPECT(frames_server_->IsOpen(), frames_server_->StrError());
149 // TODO(schuffelen): Make this a separate optional feature?
150 if (instance_.enable_audio()) {
151 auto path = config_.ForDefaultInstance().audio_server_path();
152 audio_server_ =
153 SharedFD::SocketLocalServer(path, false, SOCK_SEQPACKET, 0666);
154 CF_EXPECT(audio_server_->IsOpen(), audio_server_->StrError());
155 }
156 CF_EXPECT(InitializeVConsoles());
157 return {};
158 }
159
InitializeVConsoles()160 Result<void> InitializeVConsoles() {
161 std::vector<std::string> fifo_files = {
162 instance_.PerInstanceInternalPath("confui_fifo_vm.in"),
163 instance_.PerInstanceInternalPath("confui_fifo_vm.out"),
164 };
165 for (const auto& path : fifo_files) {
166 unlink(path.c_str());
167 }
168 std::vector<SharedFD> fds;
169 for (const auto& path : fifo_files) {
170 fds.emplace_back(CF_EXPECT(SharedFD::Fifo(path, 0660)));
171 }
172 confui_in_fd_ = fds[0];
173 confui_out_fd_ = fds[1];
174 return {};
175 }
176
177 const CuttlefishConfig& config_;
178 const CuttlefishConfig::InstanceSpecific& instance_;
179 InputConnectionsProvider& input_connections_provider_;
180 SharedFD frames_server_;
181 SharedFD audio_server_;
182 SharedFD confui_in_fd_; // host -> guest
183 SharedFD confui_out_fd_; // guest -> host
184 };
185
186 class WebRtcServer : public virtual CommandSource,
187 public DiagnosticInformation,
188 public KernelLogPipeConsumer {
189 public:
INJECT(WebRtcServer (const CuttlefishConfig & config,const CuttlefishConfig::InstanceSpecific & instance,StreamerSockets & sockets,KernelLogPipeProvider & log_pipe_provider,const CustomActionConfigProvider & custom_action_config,WebRtcController & webrtc_controller,AutoSensorsSocketPair::Type & sensors_socket_pair))190 INJECT(WebRtcServer(const CuttlefishConfig& config,
191 const CuttlefishConfig::InstanceSpecific& instance,
192 StreamerSockets& sockets,
193 KernelLogPipeProvider& log_pipe_provider,
194 const CustomActionConfigProvider& custom_action_config,
195 WebRtcController& webrtc_controller,
196 AutoSensorsSocketPair::Type& sensors_socket_pair))
197 : config_(config),
198 instance_(instance),
199 sockets_(sockets),
200 log_pipe_provider_(log_pipe_provider),
201 custom_action_config_(custom_action_config),
202 webrtc_controller_(webrtc_controller),
203 sensors_socket_pair_(sensors_socket_pair) {}
204 // DiagnosticInformation
Diagnostics() const205 std::vector<std::string> Diagnostics() const override {
206 if (!Enabled() ||
207 !(config_.ForDefaultInstance().start_webrtc_sig_server() ||
208 config_.ForDefaultInstance().start_webrtc_sig_server_proxy())) {
209 // When WebRTC is enabled but an operator other than the one launched by
210 // run_cvd is used there is no way to know the url to which to point the
211 // browser to.
212 return {};
213 }
214 std::ostringstream out;
215 out << "Point your browser to https://localhost:"
216 << config_.sig_server_port() << " to interact with the device.";
217 return {out.str()};
218 }
219
220 // CommandSource
Commands()221 Result<std::vector<MonitorCommand>> Commands() override {
222 std::vector<MonitorCommand> commands;
223 if (instance_.start_webrtc_sig_server()) {
224 Command sig_server(WebRtcSigServerBinary());
225 sig_server.AddParameter("-assets_dir=", instance_.webrtc_assets_dir());
226 sig_server.AddParameter("-use_secure_http=",
227 config_.sig_server_secure() ? "true" : "false");
228 if (!config_.webrtc_certs_dir().empty()) {
229 sig_server.AddParameter("-certs_dir=", config_.webrtc_certs_dir());
230 }
231 sig_server.AddParameter("-http_server_port=", config_.sig_server_port());
232 commands.emplace_back(std::move(sig_server));
233 }
234
235 if (instance_.start_webrtc_sig_server_proxy()) {
236 Command sig_proxy(WebRtcSigServerProxyBinary());
237 sig_proxy.AddParameter("-server_port=", config_.sig_server_port());
238 commands.emplace_back(std::move(sig_proxy));
239 }
240
241 auto stopper = [webrtc_controller = webrtc_controller_]() mutable {
242 (void)webrtc_controller.SendStopRecordingCommand();
243 return StopperResult::kStopFailure;
244 };
245
246 Command webrtc(WebRtcBinary(), KillSubprocessFallback(stopper));
247
248 webrtc.AddParameter("-group_id=", instance_.group_id());
249
250 webrtc.UnsetFromEnvironment("http_proxy");
251 sockets_.AppendCommandArguments(webrtc);
252 // Currently there is no way to ensure the signaling server will already
253 // have bound the socket to the port by the time the webrtc process runs
254 // (the common technique of doing it from the launcher is not possible here
255 // as the server library being used creates its own sockets). However, this
256 // issue is mitigated slightly by doing some retrying and backoff in the
257 // webrtc process when connecting to the websocket, so it shouldn't be an
258 // issue most of the time.
259 webrtc.AddParameter("--command_fd=", webrtc_controller_.GetClientSocket());
260 webrtc.AddParameter("-kernel_log_events_fd=", kernel_log_events_pipe_);
261 webrtc.AddParameter("-client_dir=",
262 DefaultHostArtifactsPath("usr/share/webrtc/assets"));
263
264 // TODO get from launcher params
265 const auto& actions =
266 custom_action_config_.CustomActionServers(instance_.id());
267 for (auto& action : LaunchCustomActionServers(webrtc, actions)) {
268 commands.emplace_back(std::move(action));
269 }
270
271 webrtc.AddParameter("-sensors_fd=",
272 sensors_socket_pair_->sensors_simulator_socket);
273
274 commands.emplace_back(std::move(webrtc));
275 return commands;
276 }
277
278 // SetupFeature
Enabled() const279 bool Enabled() const override {
280 return sockets_.Enabled() && instance_.enable_webrtc();
281 }
282
283 private:
Name() const284 std::string Name() const override { return "WebRtcServer"; }
Dependencies() const285 std::unordered_set<SetupFeature*> Dependencies() const override {
286 return {static_cast<SetupFeature*>(&sockets_),
287 static_cast<SetupFeature*>(&log_pipe_provider_),
288 static_cast<SetupFeature*>(&webrtc_controller_),
289 static_cast<SetupFeature*>(&sensors_socket_pair_)};
290 }
291
ResultSetup()292 Result<void> ResultSetup() override {
293 kernel_log_events_pipe_ = log_pipe_provider_.KernelLogPipe();
294 CF_EXPECT(kernel_log_events_pipe_->IsOpen(),
295 kernel_log_events_pipe_->StrError());
296 return {};
297 }
298
299 const CuttlefishConfig& config_;
300 const CuttlefishConfig::InstanceSpecific& instance_;
301 StreamerSockets& sockets_;
302 KernelLogPipeProvider& log_pipe_provider_;
303 const CustomActionConfigProvider& custom_action_config_;
304 WebRtcController& webrtc_controller_;
305 SharedFD kernel_log_events_pipe_;
306 SharedFD switches_server_;
307 AutoSensorsSocketPair::Type& sensors_socket_pair_;
308 };
309
310 } // namespace
311
312 fruit::Component<fruit::Required<
313 const CuttlefishConfig, KernelLogPipeProvider, InputConnectionsProvider,
314 const CuttlefishConfig::InstanceSpecific, const CustomActionConfigProvider,
315 WebRtcController>>
launchStreamerComponent()316 launchStreamerComponent() {
317 return fruit::createComponent()
318 .addMultibinding<CommandSource, WebRtcServer>()
319 .addMultibinding<DiagnosticInformation, WebRtcServer>()
320 .addMultibinding<KernelLogPipeConsumer, WebRtcServer>()
321 .addMultibinding<SetupFeature, StreamerSockets>()
322 .addMultibinding<SetupFeature, WebRtcServer>();
323 }
324
325 } // namespace cuttlefish
326