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_fd.h"
27 #include "common/libs/utils/files.h"
28 #include "google/rpc/code.pb.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/frontend/webrtc/screenshot_handler.h"
40 #include "host/frontend/webrtc/webrtc_command_channel.h"
41 #include "host/libs/audio_connector/server.h"
42 #include "host/libs/config/cuttlefish_config.h"
43 #include "host/libs/config/logging.h"
44 #include "host/libs/config/openwrt_args.h"
45 #include "host/libs/confui/host_mode_ctrl.h"
46 #include "host/libs/confui/host_server.h"
47 #include "host/libs/input_connector/input_connector.h"
48 #include "host/libs/screen_connector/screen_connector.h"
49 #include "webrtc_commands.pb.h"
50 
51 DEFINE_bool(multitouch, true,
52             "Whether to send multi-touch or single-touch events");
53 DEFINE_string(touch_fds, "",
54               "A list of fds to listen on for touch connections.");
55 DEFINE_int32(mouse_fd, -1, "An fd to listen on for mouse connections.");
56 DEFINE_int32(rotary_fd, -1, "An fd to listen on for rotary connections.");
57 DEFINE_int32(keyboard_fd, -1, "An fd to listen on for keyboard connections.");
58 DEFINE_int32(switches_fd, -1, "An fd to listen on for switch connections.");
59 DEFINE_int32(frame_server_fd, -1, "An fd to listen on for frame updates");
60 DEFINE_int32(kernel_log_events_fd, -1,
61              "An fd to listen on for kernel log events.");
62 DEFINE_int32(command_fd, -1, "An fd to listen to for control messages");
63 DEFINE_int32(confui_in_fd, -1,
64              "Confirmation UI virtio-console from host to guest");
65 DEFINE_int32(confui_out_fd, -1,
66              "Confirmation UI virtio-console from guest to host");
67 DEFINE_int32(sensors_in_fd, -1, "Sensors virtio-console from host to guest");
68 DEFINE_int32(sensors_out_fd, -1, "Sensors virtio-console from guest to host");
69 DEFINE_string(action_servers, "",
70               "A comma-separated list of server_name:fd pairs, "
71               "where each entry corresponds to one custom action server.");
72 DEFINE_bool(write_virtio_input, true,
73             "Whether to send input events in virtio format.");
74 DEFINE_int32(audio_server_fd, -1, "An fd to listen on for audio frames");
75 DEFINE_int32(camera_streamer_fd, -1, "An fd to send client camera frames");
76 DEFINE_string(client_dir, "webrtc", "Location of the client files");
77 DEFINE_string(group_id, "", "The group id of device");
78 
79 namespace cuttlefish {
80 
81 using webrtc_streaming::RecordingManager;
82 using webrtc_streaming::ServerConfig;
83 using webrtc_streaming::Streamer;
84 using webrtc_streaming::StreamerConfig;
85 using webrtc_streaming::VideoSink;
86 
87 constexpr auto kOpewnrtWanIpAddressName = "wan_ipaddr";
88 constexpr auto kTouchscreenPrefix = "display_";
89 constexpr auto kTouchpadPrefix = "touch_";
90 
91 class CfOperatorObserver : public webrtc_streaming::OperatorObserver {
92  public:
93   virtual ~CfOperatorObserver() = default;
OnRegistered()94   virtual void OnRegistered() override {
95     LOG(VERBOSE) << "Registered with Operator";
96   }
OnClose()97   virtual void OnClose() override {
98     LOG(ERROR) << "Connection with Operator unexpectedly closed";
99   }
OnError()100   virtual void OnError() override {
101     LOG(ERROR) << "Error encountered in connection with Operator";
102   }
103 };
CreateAudioServer()104 std::unique_ptr<AudioServer> CreateAudioServer() {
105   SharedFD audio_server_fd = SharedFD::Dup(FLAGS_audio_server_fd);
106   close(FLAGS_audio_server_fd);
107   return std::make_unique<AudioServer>(audio_server_fd);
108 }
109 
WebRtcComponent()110 fruit::Component<CustomActionConfigProvider> WebRtcComponent() {
111   return fruit::createComponent()
112       .install(ConfigFlagPlaceholder)
113       .install(CustomActionsComponent);
114 };
115 
116 fruit::Component<ScreenConnector<DisplayHandler::WebRtcScProcessedFrame>,
117                  confui::HostServer, confui::HostVirtualInput>
CreateConfirmationUIComponent(int * frames_fd,bool * frames_are_rgba,confui::PipeConnectionPair * pipe_io_pair,InputConnector * input_connector)118 CreateConfirmationUIComponent(int* frames_fd, bool* frames_are_rgba,
119                               confui::PipeConnectionPair* pipe_io_pair,
120                               InputConnector* input_connector) {
121   using ScreenConnector = DisplayHandler::ScreenConnector;
122   return fruit::createComponent()
123       .bindInstance<fruit::Annotated<WaylandScreenConnector::FramesFd, int>>(
124           *frames_fd)
125       .bindInstance<
126           fruit::Annotated<WaylandScreenConnector::FramesAreRgba, bool>>(
127           *frames_are_rgba)
128       .bindInstance(*pipe_io_pair)
129       .bind<ScreenConnectorFrameRenderer, ScreenConnector>()
130       .bindInstance(*input_connector);
131 }
132 
ControlLoop(SharedFD control_socket,DisplayHandler & display_handler,RecordingManager & recording_manager,ScreenshotHandler & screenshot_handler)133 Result<void> ControlLoop(SharedFD control_socket,
134                          DisplayHandler& display_handler,
135                          RecordingManager& recording_manager,
136                          ScreenshotHandler& screenshot_handler) {
137   WebrtcServerCommandChannel channel(control_socket);
138   while (true) {
139     webrtc::WebrtcCommandRequest request = CF_EXPECT(channel.ReceiveRequest());
140 
141     Result<void> command_result = {};
142     if (request.has_start_recording_request()) {
143       LOG(INFO) << "Received command to start recording in main.cpp.";
144       recording_manager.Start();
145     } else if (request.has_stop_recording_request()) {
146       LOG(INFO) << "Received command to stop recording in main.cpp.";
147       recording_manager.Stop();
148     } else if (request.has_screenshot_display_request()) {
149       const auto& screenshot_request = request.screenshot_display_request();
150       LOG(INFO) << "Received command to screenshot display "
151                 << screenshot_request.display_number() << "in main.cpp.";
152 
153       display_handler.AddDisplayClient();
154 
155       command_result =
156           screenshot_handler.Screenshot(screenshot_request.display_number(),
157                                         screenshot_request.screenshot_path());
158 
159       display_handler.RemoveDisplayClient();
160 
161       if (!command_result.ok()) {
162         LOG(ERROR) << "Failed to screenshot display "
163                    << screenshot_request.display_number() << " to "
164                    << screenshot_request.screenshot_path() << ":"
165                    << command_result.error().Message();
166       }
167     } else {
168       LOG(FATAL) << "Unhandled request: " << request.DebugString();
169     }
170 
171     webrtc::WebrtcCommandResponse response;
172     auto* response_status = response.mutable_status();
173     if (command_result.ok()) {
174       response_status->set_code(google::rpc::Code::OK);
175     } else {
176       response_status->set_code(google::rpc::Code::INTERNAL);
177       response_status->set_message(command_result.error().Message());
178     }
179 
180     CF_EXPECT(channel.SendResponse(response));
181   }
182 }
183 
CuttlefishMain()184 int CuttlefishMain() {
185   auto control_socket = SharedFD::Dup(FLAGS_command_fd);
186   close(FLAGS_command_fd);
187 
188   auto cvd_config = CuttlefishConfig::Get();
189   auto instance = cvd_config->ForDefaultInstance();
190 
191   cuttlefish::InputConnectorBuilder inputs_builder(
192       FLAGS_write_virtio_input ? cuttlefish::InputEventType::Virtio
193                                : cuttlefish::InputEventType::Evdev);
194 
195   const auto display_count = instance.display_configs().size();
196   const auto touch_fds = android::base::Split(FLAGS_touch_fds, ",");
197   CHECK(touch_fds.size() == display_count + instance.touchpad_configs().size())
198       << "Number of touch FDs does not match the number of configured displays "
199          "and touchpads";
200   for (int i = 0; i < touch_fds.size(); i++) {
201     int touch_fd;
202     CHECK(android::base::ParseInt(touch_fds[i], &touch_fd))
203         << "Invalid touch_fd: " << touch_fds[i];
204     // Displays are listed first, then touchpads
205     auto label_prefix =
206         i < display_count ? kTouchscreenPrefix : kTouchpadPrefix;
207     auto device_idx = i < display_count ? i : i - display_count;
208     auto device_label = fmt::format("{}{}", label_prefix, device_idx);
209     auto touch_shared_fd = SharedFD::Dup(touch_fd);
210     if (FLAGS_multitouch) {
211       inputs_builder.WithMultitouchDevice(device_label, touch_shared_fd);
212     } else {
213       inputs_builder.WithTouchDevice(device_label, touch_shared_fd);
214     }
215     close(touch_fd);
216   }
217   if (FLAGS_rotary_fd >= 0) {
218     inputs_builder.WithRotary(SharedFD::Dup(FLAGS_rotary_fd));
219     close(FLAGS_rotary_fd);
220   }
221   if (FLAGS_mouse_fd >= 0) {
222     inputs_builder.WithMouse(SharedFD::Dup(FLAGS_mouse_fd));
223     close(FLAGS_mouse_fd);
224   }
225   if (FLAGS_keyboard_fd >= 0) {
226     inputs_builder.WithKeyboard(SharedFD::Dup(FLAGS_keyboard_fd));
227     close(FLAGS_keyboard_fd);
228   }
229   if (FLAGS_switches_fd >= 0) {
230     inputs_builder.WithSwitches(SharedFD::Dup(FLAGS_switches_fd));
231     close(FLAGS_switches_fd);
232   }
233 
234   auto input_connector = std::move(inputs_builder).Build();
235 
236   auto kernel_log_events_client = SharedFD::Dup(FLAGS_kernel_log_events_fd);
237   close(FLAGS_kernel_log_events_fd);
238 
239   confui::PipeConnectionPair conf_ui_comm_fd_pair{
240       .from_guest_ = SharedFD::Dup(FLAGS_confui_out_fd),
241       .to_guest_ = SharedFD::Dup(FLAGS_confui_in_fd)};
242   close(FLAGS_confui_in_fd);
243   close(FLAGS_confui_out_fd);
244 
245   int frames_fd = FLAGS_frame_server_fd;
246   bool frames_are_rgba = true;
247   fruit::Injector<ScreenConnector<DisplayHandler::WebRtcScProcessedFrame>,
248                   confui::HostServer, confui::HostVirtualInput>
249       conf_ui_components_injector(CreateConfirmationUIComponent,
250                                   std::addressof(frames_fd),
251                                   std::addressof(frames_are_rgba),
252                                   &conf_ui_comm_fd_pair, input_connector.get());
253   auto& screen_connector =
254       conf_ui_components_injector.get<DisplayHandler::ScreenConnector&>();
255 
256   auto client_server = ClientFilesServer::New(FLAGS_client_dir);
257   CHECK(client_server) << "Failed to initialize client files server";
258   auto& host_confui_server =
259       conf_ui_components_injector.get<confui::HostServer&>();
260   auto& confui_virtual_input =
261       conf_ui_components_injector.get<confui::HostVirtualInput&>();
262 
263   StreamerConfig streamer_config;
264 
265   streamer_config.device_id = instance.webrtc_device_id();
266   streamer_config.group_id = FLAGS_group_id;
267   streamer_config.client_files_port = client_server->port();
268   streamer_config.tcp_port_range = instance.webrtc_tcp_port_range();
269   streamer_config.udp_port_range = instance.webrtc_udp_port_range();
270   streamer_config.openwrt_device_id =
271       cvd_config->Instances()[0].webrtc_device_id();
272   streamer_config.openwrt_addr = OpenwrtArgsFromConfig(
273       cvd_config->Instances()[0])[kOpewnrtWanIpAddressName];
274   streamer_config.adb_port = instance.adb_host_port();
275   streamer_config.control_env_proxy_server_path =
276       instance.grpc_socket_path() + "/ControlEnvProxyServer.sock";
277   streamer_config.operator_server.addr = cvd_config->sig_server_address();
278   streamer_config.operator_server.port = cvd_config->sig_server_port();
279   streamer_config.operator_server.path = cvd_config->sig_server_path();
280   if (cvd_config->sig_server_secure()) {
281     streamer_config.operator_server.security =
282         cvd_config->sig_server_strict()
283             ? ServerConfig::Security::kStrict
284             : ServerConfig::Security::kAllowSelfSigned;
285   } else {
286     streamer_config.operator_server.security =
287         ServerConfig::Security::kInsecure;
288   }
289   streamer_config.enable_mouse = instance.enable_mouse();
290 
291   KernelLogEventsHandler kernel_logs_event_handler(kernel_log_events_client);
292 
293   std::shared_ptr<webrtc_streaming::LightsObserver> lights_observer;
294   if (instance.lights_server_port()) {
295     lights_observer = std::make_shared<webrtc_streaming::LightsObserver>(
296         instance.lights_server_port(), instance.vsock_guest_cid(),
297         instance.vhost_user_vsock());
298     lights_observer->Start();
299   }
300 
301   auto observer_factory = std::make_shared<CfConnectionObserverFactory>(
302       confui_virtual_input, &kernel_logs_event_handler, lights_observer);
303 
304   RecordingManager recording_manager;
305 
306   ScreenshotHandler screenshot_handler;
307 
308   auto streamer =
309       Streamer::Create(streamer_config, recording_manager, observer_factory);
310   CHECK(streamer) << "Could not create streamer";
311 
312   auto display_handler = std::make_shared<DisplayHandler>(
313       *streamer, screenshot_handler, screen_connector);
314 
315   if (instance.camera_server_port()) {
316     auto camera_controller = streamer->AddCamera(instance.camera_server_port(),
317                                                  instance.vsock_guest_cid(),
318                                                  instance.vhost_user_vsock());
319     observer_factory->SetCameraHandler(camera_controller);
320     streamer->SetHardwareSpec("camera_passthrough", true);
321   }
322 
323   observer_factory->SetDisplayHandler(display_handler);
324 
325   const auto touchpad_configs = instance.touchpad_configs();
326   for (int i = 0; i < touchpad_configs.size(); i++) {
327     streamer->AddTouchpad(kTouchpadPrefix + std::to_string(i),
328                           touchpad_configs[i].width,
329                           touchpad_configs[i].height);
330   }
331 
332   streamer->SetHardwareSpec("CPUs", instance.cpus());
333   streamer->SetHardwareSpec("RAM", std::to_string(instance.memory_mb()) + " mb");
334 
335   std::string user_friendly_gpu_mode;
336   if (instance.gpu_mode() == kGpuModeGuestSwiftshader) {
337     user_friendly_gpu_mode = "SwiftShader (Guest CPU Rendering)";
338   } else if (instance.gpu_mode() == kGpuModeDrmVirgl) {
339     user_friendly_gpu_mode =
340         "VirglRenderer (Accelerated Rendering using Host OpenGL)";
341   } else if (instance.gpu_mode() == kGpuModeGfxstream) {
342     user_friendly_gpu_mode =
343         "Gfxstream (Accelerated Rendering using Host OpenGL and Vulkan)";
344   } else if (instance.gpu_mode() == kGpuModeGfxstreamGuestAngle) {
345     user_friendly_gpu_mode =
346         "Gfxstream (Accelerated Rendering using Host Vulkan)";
347   } else {
348     user_friendly_gpu_mode = instance.gpu_mode();
349   }
350   streamer->SetHardwareSpec("GPU Mode", user_friendly_gpu_mode);
351 
352   std::shared_ptr<AudioHandler> audio_handler;
353   if (instance.enable_audio()) {
354     auto audio_stream = streamer->AddAudioStream("audio");
355     auto audio_server = CreateAudioServer();
356     auto audio_source = streamer->GetAudioSource();
357     audio_handler = std::make_shared<AudioHandler>(std::move(audio_server),
358                                                    audio_stream, audio_source);
359   }
360 
361   // Parse the -action_servers flag, storing a map of action server name -> fd
362   std::map<std::string, int> action_server_fds;
363   for (const std::string& action_server :
364        android::base::Split(FLAGS_action_servers, ",")) {
365     if (action_server.empty()) {
366       continue;
367     }
368     const std::vector<std::string> server_and_fd =
369         android::base::Split(action_server, ":");
370     CHECK(server_and_fd.size() == 2)
371         << "Wrong format for action server flag: " << action_server;
372     std::string server = server_and_fd[0];
373     int fd = std::stoi(server_and_fd[1]);
374     action_server_fds[server] = fd;
375   }
376 
377   fruit::Injector<CustomActionConfigProvider> injector(WebRtcComponent);
378   for (auto& fragment : injector.getMultibindings<ConfigFragment>()) {
379     CHECK(cvd_config->LoadFragment(*fragment))
380         << "Failed to load config fragment";
381   }
382 
383   const auto& actions_provider = injector.get<CustomActionConfigProvider&>();
384 
385   for (const auto& custom_action :
386        actions_provider.CustomShellActions(instance.id())) {
387     const auto button = custom_action.button;
388     streamer->AddCustomControlPanelButtonWithShellCommand(
389         button.command, button.title, button.icon_name,
390         custom_action.shell_command);
391   }
392 
393   for (const auto& custom_action :
394        actions_provider.CustomActionServers(instance.id())) {
395     if (action_server_fds.find(custom_action.server) ==
396         action_server_fds.end()) {
397       LOG(ERROR) << "Custom action server not provided as command line flag: "
398                  << custom_action.server;
399       continue;
400     }
401     LOG(INFO) << "Connecting to custom action server " << custom_action.server;
402 
403     int fd = action_server_fds[custom_action.server];
404     SharedFD custom_action_server = SharedFD::Dup(fd);
405     close(fd);
406 
407     if (custom_action_server->IsOpen()) {
408       std::vector<std::string> commands_for_this_server;
409       for (const auto& button : custom_action.buttons) {
410         streamer->AddCustomControlPanelButton(button.command, button.title,
411                                               button.icon_name);
412         commands_for_this_server.push_back(button.command);
413       }
414       observer_factory->AddCustomActionServer(custom_action_server,
415                                               commands_for_this_server);
416     } else {
417       LOG(ERROR) << "Error connecting to custom action server: "
418                  << custom_action.server;
419     }
420   }
421 
422   for (const auto& custom_action :
423        actions_provider.CustomDeviceStateActions(instance.id())) {
424     const auto button = custom_action.button;
425     streamer->AddCustomControlPanelButtonWithDeviceStates(
426         button.command, button.title, button.icon_name,
427         custom_action.device_states);
428   }
429 
430   std::shared_ptr<webrtc_streaming::OperatorObserver> operator_observer(
431       new CfOperatorObserver());
432   streamer->Register(operator_observer);
433 
434   std::thread control_thread([&]() {
435     auto result = ControlLoop(control_socket, *display_handler,
436                               recording_manager, screenshot_handler);
437     if (!result.ok()) {
438       LOG(ERROR) << "Webrtc control loop error: " << result.error().Message();
439     }
440     LOG(DEBUG) << "Webrtc control thread exiting.";
441   });
442 
443   if (audio_handler) {
444     audio_handler->Start();
445   }
446   host_confui_server.Start();
447 
448   if (instance.record_screen()) {
449     LOG(VERBOSE) << "Waiting for recording manager initializing.";
450     recording_manager.WaitForSources(instance.display_configs().size());
451     recording_manager.Start();
452   }
453 
454   display_handler->Loop();
455 
456   return 0;
457 }
458 
459 }  // namespace cuttlefish
460 
main(int argc,char ** argv)461 int main(int argc, char** argv) {
462   cuttlefish::DefaultSubprocessLogging(argv);
463   ::gflags::ParseCommandLineFlags(&argc, &argv, true);
464   return cuttlefish::CuttlefishMain();
465 }