1 /*
2  * Copyright (C) 2020 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 <memory>
18 
19 #include <android-base/logging.h>
20 #include <android-base/parseint.h>
21 #include <android-base/strings.h>
22 #include <fruit/fruit.h>
23 #include <gflags/gflags.h>
24 #include <libyuv.h>
25 
26 #include "common/libs/fs/shared_buf.h"
27 #include "common/libs/fs/shared_fd.h"
28 #include "common/libs/utils/files.h"
29 #include "host/frontend/webrtc/audio_handler.h"
30 #include "host/frontend/webrtc/client_server.h"
31 #include "host/frontend/webrtc/connection_observer.h"
32 #include "host/frontend/webrtc/display_handler.h"
33 #include "host/frontend/webrtc/kernel_log_events_handler.h"
34 #include "host/frontend/webrtc/libdevice/camera_controller.h"
35 #include "host/frontend/webrtc/libdevice/lights_observer.h"
36 #include "host/frontend/webrtc/libdevice/local_recorder.h"
37 #include "host/frontend/webrtc/libdevice/streamer.h"
38 #include "host/frontend/webrtc/libdevice/video_sink.h"
39 #include "host/libs/audio_connector/server.h"
40 #include "host/libs/config/cuttlefish_config.h"
41 #include "host/libs/config/logging.h"
42 #include "host/libs/config/openwrt_args.h"
43 #include "host/libs/input_connector/socket_input_connector.h"
44 
45 DEFINE_bool(multitouch, true,
46             "Whether to send multi-touch or single-touch events");
47 DEFINE_string(touch_fds, "",
48               "A list of fds to listen on for touch connections.");
49 DEFINE_int32(rotary_fd, -1, "An fd to listen on for rotary connections.");
50 DEFINE_int32(keyboard_fd, -1, "An fd to listen on for keyboard connections.");
51 DEFINE_int32(switches_fd, -1, "An fd to listen on for switch connections.");
52 DEFINE_int32(frame_server_fd, -1, "An fd to listen on for frame updates");
53 DEFINE_int32(kernel_log_events_fd, -1,
54              "An fd to listen on for kernel log events.");
55 DEFINE_int32(command_fd, -1, "An fd to listen to for control messages");
56 DEFINE_int32(confui_in_fd, -1,
57              "Confirmation UI virtio-console from host to guest");
58 DEFINE_int32(confui_out_fd, -1,
59              "Confirmation UI virtio-console from guest to host");
60 DEFINE_int32(sensors_in_fd, -1, "Sensors virtio-console from host to guest");
61 DEFINE_int32(sensors_out_fd, -1, "Sensors virtio-console from guest to host");
62 DEFINE_string(action_servers, "",
63               "A comma-separated list of server_name:fd pairs, "
64               "where each entry corresponds to one custom action server.");
65 DEFINE_bool(write_virtio_input, true,
66             "Whether to send input events in virtio format.");
67 DEFINE_int32(audio_server_fd, -1, "An fd to listen on for audio frames");
68 DEFINE_int32(camera_streamer_fd, -1, "An fd to send client camera frames");
69 DEFINE_string(client_dir, "webrtc", "Location of the client files");
70 DEFINE_string(group_id, "", "The group id of device");
71 
72 using cuttlefish::AudioHandler;
73 using cuttlefish::CfConnectionObserverFactory;
74 using cuttlefish::DisplayHandler;
75 using cuttlefish::KernelLogEventsHandler;
76 using cuttlefish::webrtc_streaming::RecordingManager;
77 using cuttlefish::webrtc_streaming::ServerConfig;
78 using cuttlefish::webrtc_streaming::Streamer;
79 using cuttlefish::webrtc_streaming::StreamerConfig;
80 using cuttlefish::webrtc_streaming::VideoSink;
81 
82 constexpr auto kOpewnrtWanIpAddressName = "wan_ipaddr";
83 constexpr auto kTouchscreenPrefix = "display_";
84 constexpr auto kTouchpadPrefix = "touch_";
85 
86 class CfOperatorObserver
87     : public cuttlefish::webrtc_streaming::OperatorObserver {
88  public:
89   virtual ~CfOperatorObserver() = default;
OnRegistered()90   virtual void OnRegistered() override {
91     LOG(VERBOSE) << "Registered with Operator";
92   }
OnClose()93   virtual void OnClose() override {
94     LOG(ERROR) << "Connection with Operator unexpectedly closed";
95   }
OnError()96   virtual void OnError() override {
97     LOG(ERROR) << "Error encountered in connection with Operator";
98   }
99 };
CreateAudioServer()100 std::unique_ptr<cuttlefish::AudioServer> CreateAudioServer() {
101   cuttlefish::SharedFD audio_server_fd =
102       cuttlefish::SharedFD::Dup(FLAGS_audio_server_fd);
103   close(FLAGS_audio_server_fd);
104   return std::make_unique<cuttlefish::AudioServer>(audio_server_fd);
105 }
106 
WebRtcComponent()107 fruit::Component<cuttlefish::CustomActionConfigProvider> WebRtcComponent() {
108   return fruit::createComponent()
109       .install(cuttlefish::ConfigFlagPlaceholder)
110       .install(cuttlefish::CustomActionsComponent);
111 };
112 
main(int argc,char ** argv)113 int main(int argc, char** argv) {
114   cuttlefish::DefaultSubprocessLogging(argv);
115   ::gflags::ParseCommandLineFlags(&argc, &argv, true);
116 
117   auto control_socket = cuttlefish::SharedFD::Dup(FLAGS_command_fd);
118   close(FLAGS_command_fd);
119 
120   auto cvd_config = cuttlefish::CuttlefishConfig::Get();
121   auto instance = cvd_config->ForDefaultInstance();
122 
123   cuttlefish::InputSocketsConnectorBuilder inputs_builder(
124       FLAGS_write_virtio_input ? cuttlefish::InputEventType::Virtio
125                                : cuttlefish::InputEventType::Evdev);
126 
127   const auto display_count = instance.display_configs().size();
128   const auto touch_fds = android::base::Split(FLAGS_touch_fds, ",");
129   CHECK(touch_fds.size() == display_count + instance.touchpad_configs().size())
130       << "Number of touch FDs does not match the number of configured displays "
131          "and touchpads";
132   for (int i = 0; i < touch_fds.size(); i++) {
133     int touch_fd;
134     CHECK(android::base::ParseInt(touch_fds[i], &touch_fd))
135         << "Invalid touch_fd: " << touch_fds[i];
136     // Displays are listed first, then touchpads
137     auto label_prefix =
138         i < display_count ? kTouchscreenPrefix : kTouchpadPrefix;
139     auto device_idx = i < display_count ? i : i - display_count;
140     auto device_label = fmt::format("{}{}", label_prefix, device_idx);
141     auto touch_shared_fd = cuttlefish::SharedFD::Dup(touch_fd);
142     if (FLAGS_multitouch) {
143       inputs_builder.WithMultitouchDevice(device_label, touch_shared_fd);
144     } else {
145       inputs_builder.WithTouchDevice(device_label, touch_shared_fd);
146     }
147     close(touch_fd);
148   }
149   if (FLAGS_rotary_fd >= 0) {
150     inputs_builder.WithRotary(cuttlefish::SharedFD::Dup(FLAGS_rotary_fd));
151     close(FLAGS_rotary_fd);
152   }
153   if (FLAGS_keyboard_fd >= 0) {
154     inputs_builder.WithKeyboard(cuttlefish::SharedFD::Dup(FLAGS_keyboard_fd));
155     close(FLAGS_keyboard_fd);
156   }
157   if (FLAGS_switches_fd >= 0) {
158     inputs_builder.WithSwitches(cuttlefish::SharedFD::Dup(FLAGS_switches_fd));
159     close(FLAGS_switches_fd);
160   }
161 
162   auto input_connector = std::move(inputs_builder).Build();
163 
164   auto kernel_log_events_client =
165       cuttlefish::SharedFD::Dup(FLAGS_kernel_log_events_fd);
166   close(FLAGS_kernel_log_events_fd);
167 
168   auto client_server = cuttlefish::ClientFilesServer::New(FLAGS_client_dir);
169   CHECK(client_server) << "Failed to initialize client files server";
170 
171   StreamerConfig streamer_config;
172 
173   streamer_config.device_id = instance.webrtc_device_id();
174   streamer_config.group_id = FLAGS_group_id;
175   streamer_config.client_files_port = client_server->port();
176   streamer_config.tcp_port_range = instance.webrtc_tcp_port_range();
177   streamer_config.udp_port_range = instance.webrtc_udp_port_range();
178   streamer_config.openwrt_device_id =
179       cvd_config->Instances()[0].webrtc_device_id();
180   streamer_config.openwrt_addr = OpenwrtArgsFromConfig(
181       cvd_config->Instances()[0])[kOpewnrtWanIpAddressName];
182   streamer_config.control_env_proxy_server_path =
183       instance.grpc_socket_path() + "/ControlEnvProxyServer.sock";
184   streamer_config.operator_server.addr = cvd_config->sig_server_address();
185   streamer_config.operator_server.port = cvd_config->sig_server_port();
186   streamer_config.operator_server.path = cvd_config->sig_server_path();
187   if (cvd_config->sig_server_secure()) {
188     streamer_config.operator_server.security =
189         cvd_config->sig_server_strict()
190             ? ServerConfig::Security::kStrict
191             : ServerConfig::Security::kAllowSelfSigned;
192   } else {
193     streamer_config.operator_server.security =
194         ServerConfig::Security::kInsecure;
195   }
196 
197   KernelLogEventsHandler kernel_logs_event_handler(kernel_log_events_client);
198 
199   std::shared_ptr<cuttlefish::webrtc_streaming::LightsObserver> lights_observer;
200   if (instance.lights_server_port()) {
201     lights_observer =
202         std::make_shared<cuttlefish::webrtc_streaming::LightsObserver>(
203             instance.lights_server_port(), instance.vsock_guest_cid(),
204             instance.vhost_user_vsock());
205     lights_observer->Start();
206   }
207 
208   auto observer_factory = std::make_shared<CfConnectionObserverFactory>(
209       *input_connector.get(), &kernel_logs_event_handler, lights_observer);
210 
211   RecordingManager recording_manager;
212 
213   auto streamer =
214       Streamer::Create(streamer_config, recording_manager, observer_factory);
215   CHECK(streamer) << "Could not create streamer";
216 
217   int frames_fd = FLAGS_frame_server_fd;
218   bool frames_are_rgba = !instance.guest_uses_bgra_framebuffers();
219   auto display_handler =
220       std::make_shared<DisplayHandler>(*streamer, frames_fd, frames_are_rgba);
221 
222   if (instance.camera_server_port()) {
223     auto camera_controller = streamer->AddCamera(instance.camera_server_port(),
224                                                  instance.vsock_guest_cid(),
225                                                  instance.vhost_user_vsock());
226     observer_factory->SetCameraHandler(camera_controller);
227     streamer->SetHardwareSpec("camera_passthrough", true);
228   }
229 
230   observer_factory->SetDisplayHandler(display_handler);
231 
232   const auto touchpad_configs = instance.touchpad_configs();
233   for (int i = 0; i < touchpad_configs.size(); i++) {
234     streamer->AddTouchpad(kTouchpadPrefix + std::to_string(i),
235                           touchpad_configs[i].width,
236                           touchpad_configs[i].height);
237   }
238 
239   streamer->SetHardwareSpec("CPUs", instance.cpus());
240   streamer->SetHardwareSpec("RAM", std::to_string(instance.memory_mb()) + " mb");
241 
242   std::string user_friendly_gpu_mode;
243   if (instance.gpu_mode() == cuttlefish::kGpuModeGuestSwiftshader) {
244     user_friendly_gpu_mode = "SwiftShader (Guest CPU Rendering)";
245   } else if (instance.gpu_mode() == cuttlefish::kGpuModeDrmVirgl) {
246     user_friendly_gpu_mode =
247         "VirglRenderer (Accelerated Rendering using Host OpenGL)";
248   } else if (instance.gpu_mode() == cuttlefish::kGpuModeGfxstream) {
249     user_friendly_gpu_mode =
250         "Gfxstream (Accelerated Rendering using Host OpenGL and Vulkan)";
251   } else if (instance.gpu_mode() == cuttlefish::kGpuModeGfxstreamGuestAngle) {
252     user_friendly_gpu_mode =
253         "Gfxstream (Accelerated Rendering using Host Vulkan)";
254   } else {
255     user_friendly_gpu_mode = instance.gpu_mode();
256   }
257   streamer->SetHardwareSpec("GPU Mode", user_friendly_gpu_mode);
258 
259   std::shared_ptr<AudioHandler> audio_handler;
260   if (instance.enable_audio()) {
261     auto audio_stream = streamer->AddAudioStream("audio");
262     auto audio_server = CreateAudioServer();
263     auto audio_source = streamer->GetAudioSource();
264     audio_handler = std::make_shared<AudioHandler>(std::move(audio_server),
265                                                    audio_stream, audio_source);
266   }
267 
268   // Parse the -action_servers flag, storing a map of action server name -> fd
269   std::map<std::string, int> action_server_fds;
270   for (const std::string& action_server :
271        android::base::Split(FLAGS_action_servers, ",")) {
272     if (action_server.empty()) {
273       continue;
274     }
275     const std::vector<std::string> server_and_fd =
276         android::base::Split(action_server, ":");
277     CHECK(server_and_fd.size() == 2)
278         << "Wrong format for action server flag: " << action_server;
279     std::string server = server_and_fd[0];
280     int fd = std::stoi(server_and_fd[1]);
281     action_server_fds[server] = fd;
282   }
283 
284   fruit::Injector<cuttlefish::CustomActionConfigProvider> injector(
285       WebRtcComponent);
286   for (auto& fragment :
287        injector.getMultibindings<cuttlefish::ConfigFragment>()) {
288     CHECK(cvd_config->LoadFragment(*fragment))
289         << "Failed to load config fragment";
290   }
291 
292   const auto& actions_provider =
293       injector.get<cuttlefish::CustomActionConfigProvider&>();
294 
295   for (const auto& custom_action :
296        actions_provider.CustomShellActions(instance.id())) {
297     const auto button = custom_action.button;
298     streamer->AddCustomControlPanelButtonWithShellCommand(
299         button.command, button.title, button.icon_name,
300         custom_action.shell_command);
301   }
302 
303   for (const auto& custom_action :
304        actions_provider.CustomActionServers(instance.id())) {
305     if (action_server_fds.find(custom_action.server) ==
306         action_server_fds.end()) {
307       LOG(ERROR) << "Custom action server not provided as command line flag: "
308                  << custom_action.server;
309       continue;
310     }
311     LOG(INFO) << "Connecting to custom action server " << custom_action.server;
312 
313     int fd = action_server_fds[custom_action.server];
314     cuttlefish::SharedFD custom_action_server = cuttlefish::SharedFD::Dup(fd);
315     close(fd);
316 
317     if (custom_action_server->IsOpen()) {
318       std::vector<std::string> commands_for_this_server;
319       for (const auto& button : custom_action.buttons) {
320         streamer->AddCustomControlPanelButton(button.command, button.title,
321                                               button.icon_name);
322         commands_for_this_server.push_back(button.command);
323       }
324       observer_factory->AddCustomActionServer(custom_action_server,
325                                               commands_for_this_server);
326     } else {
327       LOG(ERROR) << "Error connecting to custom action server: "
328                  << custom_action.server;
329     }
330   }
331 
332   for (const auto& custom_action :
333        actions_provider.CustomDeviceStateActions(instance.id())) {
334     const auto button = custom_action.button;
335     streamer->AddCustomControlPanelButtonWithDeviceStates(
336         button.command, button.title, button.icon_name,
337         custom_action.device_states);
338   }
339 
340   std::shared_ptr<cuttlefish::webrtc_streaming::OperatorObserver> operator_observer(
341       new CfOperatorObserver());
342   streamer->Register(operator_observer);
343 
344   std::thread control_thread([control_socket, &recording_manager]() {
345     std::string message = "_";
346     int read_ret;
347     while ((read_ret = cuttlefish::ReadExact(control_socket, &message)) > 0) {
348       LOG(VERBOSE) << "received control message: " << message;
349       if (message[0] == 'T') {
350         LOG(INFO) << "Received command to start recording in main.cpp.";
351         recording_manager.Start();
352       } else if (message[0] == 'C') {
353         LOG(INFO) << "Received command to stop recording in main.cpp.";
354         recording_manager.Stop();
355       }
356       // Send feedback an indication of command received.
357       CHECK(cuttlefish::WriteAll(control_socket, "Y") == 1) << "Failed to send response: "
358                                                             << control_socket->StrError();
359     }
360     LOG(DEBUG) << "control socket closed";
361   });
362 
363   if (audio_handler) {
364     audio_handler->Start();
365   }
366 
367   if (instance.record_screen()) {
368     LOG(VERBOSE) << "Waiting for recording manager initializing.";
369     recording_manager.WaitForSources(instance.display_configs().size());
370     recording_manager.Start();
371   }
372 
373   control_thread.join();
374 
375   return 0;
376 }
377