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.h"
17
18 #include <android-base/logging.h>
19 #include <string>
20 #include <utility>
21
22 #include "common/libs/fs/shared_buf.h"
23 #include "common/libs/fs/shared_fd.h"
24 #include "common/libs/utils/files.h"
25 #include "host/libs/config/cuttlefish_config.h"
26 #include "host/libs/config/known_paths.h"
27 #include "host/libs/vm_manager/crosvm_manager.h"
28 #include "host/libs/vm_manager/qemu_manager.h"
29
30 namespace cuttlefish {
31
32 namespace {
33
CreateUnixInputServer(const std::string & path)34 SharedFD CreateUnixInputServer(const std::string& path) {
35 auto server =
36 SharedFD::SocketLocalServer(path.c_str(), false, SOCK_STREAM, 0666);
37 if (!server->IsOpen()) {
38 LOG(ERROR) << "Unable to create unix input server: " << server->StrError();
39 return {};
40 }
41 return server;
42 }
43
44 // Creates the frame and input sockets and add the relevant arguments to the vnc
45 // server and webrtc commands
CreateStreamerServers(Command * cmd,const CuttlefishConfig & config)46 void CreateStreamerServers(Command* cmd, const CuttlefishConfig& config) {
47 SharedFD touch_server;
48 SharedFD keyboard_server;
49
50 auto instance = config.ForDefaultInstance();
51 if (config.vm_manager() == vm_manager::QemuManager::name()) {
52 cmd->AddParameter("-write_virtio_input");
53
54 touch_server =
55 SharedFD::VsockServer(instance.touch_server_port(), SOCK_STREAM);
56 keyboard_server =
57 SharedFD::VsockServer(instance.keyboard_server_port(), SOCK_STREAM);
58 } else {
59 touch_server = CreateUnixInputServer(instance.touch_socket_path());
60 keyboard_server = CreateUnixInputServer(instance.keyboard_socket_path());
61 }
62 if (!touch_server->IsOpen()) {
63 LOG(ERROR) << "Could not open touch server: " << touch_server->StrError();
64 return;
65 }
66 cmd->AddParameter("-touch_fd=", touch_server);
67
68 if (!keyboard_server->IsOpen()) {
69 LOG(ERROR) << "Could not open keyboard server: "
70 << keyboard_server->StrError();
71 return;
72 }
73 cmd->AddParameter("-keyboard_fd=", keyboard_server);
74
75 if (config.enable_webrtc() &&
76 config.vm_manager() == vm_manager::CrosvmManager::name()) {
77 SharedFD switches_server =
78 CreateUnixInputServer(instance.switches_socket_path());
79 if (!switches_server->IsOpen()) {
80 LOG(ERROR) << "Could not open switches server: "
81 << switches_server->StrError();
82 return;
83 }
84 cmd->AddParameter("-switches_fd=", switches_server);
85 }
86
87 SharedFD frames_server = CreateUnixInputServer(instance.frames_socket_path());
88 if (!frames_server->IsOpen()) {
89 LOG(ERROR) << "Could not open frames server: " << frames_server->StrError();
90 return;
91 }
92 cmd->AddParameter("-frame_server_fd=", frames_server);
93
94 if (config.enable_audio()) {
95 auto path = config.ForDefaultInstance().audio_server_path();
96 auto audio_server =
97 SharedFD::SocketLocalServer(path.c_str(), false, SOCK_SEQPACKET, 0666);
98 if (!audio_server->IsOpen()) {
99 LOG(ERROR) << "Could not create audio server: "
100 << audio_server->StrError();
101 return;
102 }
103 cmd->AddParameter("--audio_server_fd=", audio_server);
104 }
105 }
106
LaunchCustomActionServers(Command & webrtc_cmd,const CuttlefishConfig & config)107 std::vector<Command> LaunchCustomActionServers(Command& webrtc_cmd,
108 const CuttlefishConfig& config) {
109 bool first = true;
110 std::vector<Command> commands;
111 for (const auto& custom_action : config.custom_actions()) {
112 if (custom_action.server) {
113 // Create a socket pair that will be used for communication between
114 // WebRTC and the action server.
115 SharedFD webrtc_socket, action_server_socket;
116 if (!SharedFD::SocketPair(AF_LOCAL, SOCK_STREAM, 0, &webrtc_socket,
117 &action_server_socket)) {
118 LOG(ERROR) << "Unable to create custom action server socket pair: "
119 << strerror(errno);
120 continue;
121 }
122
123 // Launch the action server, providing its socket pair fd as the only
124 // argument.
125 std::string binary = "bin/" + *(custom_action.server);
126 Command command(DefaultHostArtifactsPath(binary));
127 command.AddParameter(action_server_socket);
128 commands.emplace_back(std::move(command));
129
130 // Pass the WebRTC socket pair fd to WebRTC.
131 if (first) {
132 first = false;
133 webrtc_cmd.AddParameter("-action_servers=", *custom_action.server, ":",
134 webrtc_socket);
135 } else {
136 webrtc_cmd.AppendToLastParameter(",", *custom_action.server, ":",
137 webrtc_socket);
138 }
139 }
140 }
141 return commands;
142 }
143
144 } // namespace
145
LaunchVNCServer(const CuttlefishConfig & config)146 std::vector<Command> LaunchVNCServer(const CuttlefishConfig& config) {
147 auto instance = config.ForDefaultInstance();
148 // Launch the vnc server, don't wait for it to complete
149 auto port_options = "-port=" + std::to_string(instance.vnc_server_port());
150 Command vnc_server(VncServerBinary());
151 vnc_server.AddParameter(port_options);
152
153 CreateStreamerServers(&vnc_server, config);
154
155 std::vector<Command> commands;
156 commands.emplace_back(std::move(vnc_server));
157 return std::move(commands);
158 }
159
LaunchWebRTC(const CuttlefishConfig & config,SharedFD kernel_log_events_pipe)160 std::vector<Command> LaunchWebRTC(const CuttlefishConfig& config,
161 SharedFD kernel_log_events_pipe) {
162 std::vector<Command> commands;
163 if (config.ForDefaultInstance().start_webrtc_sig_server()) {
164 Command sig_server(WebRtcSigServerBinary());
165 sig_server.AddParameter("-assets_dir=", config.webrtc_assets_dir());
166 if (!config.webrtc_certs_dir().empty()) {
167 sig_server.AddParameter("-certs_dir=", config.webrtc_certs_dir());
168 }
169 sig_server.AddParameter("-http_server_port=", config.sig_server_port());
170 commands.emplace_back(std::move(sig_server));
171 }
172
173 // Currently there is no way to ensure the signaling server will already have
174 // bound the socket to the port by the time the webrtc process runs (the
175 // common technique of doing it from the launcher is not possible here as the
176 // server library being used creates its own sockets). However, this issue is
177 // mitigated slightly by doing some retrying and backoff in the webrtc process
178 // when connecting to the websocket, so it shouldn't be an issue most of the
179 // time.
180 SharedFD client_socket;
181 SharedFD host_socket;
182 CHECK(SharedFD::SocketPair(AF_LOCAL, SOCK_STREAM, 0, &client_socket,
183 &host_socket))
184 << "Could not open command socket for webRTC";
185
186 auto stopper = [host_socket = std::move(host_socket)](Subprocess* proc) {
187 struct timeval timeout;
188 timeout.tv_sec = 3;
189 timeout.tv_usec = 0;
190 CHECK(host_socket->SetSockOpt(SOL_SOCKET, SO_RCVTIMEO, &timeout,
191 sizeof(timeout)) == 0)
192 << "Could not set receive timeout";
193
194 WriteAll(host_socket, "C");
195 char response[1];
196 int read_ret = host_socket->Read(response, sizeof(response));
197 if (read_ret != 0) {
198 LOG(ERROR) << "Failed to read response from webrtc";
199 }
200 cuttlefish::KillSubprocess(proc);
201 return true;
202 };
203
204 Command webrtc(WebRtcBinary(), SubprocessStopper(stopper));
205
206 webrtc.UnsetFromEnvironment({"http_proxy"});
207
208 CreateStreamerServers(&webrtc, config);
209
210 webrtc.AddParameter("--command_fd=", client_socket);
211 webrtc.AddParameter("-kernel_log_events_fd=", kernel_log_events_pipe);
212
213 auto actions = LaunchCustomActionServers(webrtc, config);
214
215 // TODO get from launcher params
216 commands.emplace_back(std::move(webrtc));
217 for (auto& action : actions) {
218 commands.emplace_back(std::move(action));
219 }
220
221 return commands;
222 }
223
224 } // namespace cuttlefish
225