• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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