1 /* 2 * Copyright (C) 2021 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 #pragma once 18 19 #include <atomic> 20 #include <cstdint> 21 #include <memory> 22 #include <mutex> 23 #include <string> 24 #include <thread> 25 #include <unordered_map> 26 #include <vector> 27 28 #include <android-base/logging.h> 29 #include <teeui/utils.h> 30 31 #include "common/libs/concurrency/multiplexer.h" 32 #include "common/libs/concurrency/semaphore.h" 33 #include "common/libs/confui/confui.h" 34 #include "common/libs/fs/shared_fd.h" 35 #include "host/commands/kernel_log_monitor/utils.h" 36 #include "host/libs/config/logging.h" 37 #include "host/libs/confui/host_mode_ctrl.h" 38 #include "host/libs/confui/host_virtual_input.h" 39 #include "host/libs/confui/server_common.h" 40 #include "host/libs/confui/session.h" 41 #include "host/libs/screen_connector/screen_connector.h" 42 43 namespace cuttlefish { 44 namespace confui { 45 class HostServer : public HostVirtualInput { 46 public: 47 static HostServer& Get( 48 HostModeCtrl& host_mode_ctrl, 49 cuttlefish::ScreenConnectorFrameRenderer& screen_connector); 50 51 void Start(); // start this server itself ~HostServer()52 virtual ~HostServer() {} 53 54 // implement input interfaces. called by webRTC 55 void TouchEvent(const int x, const int y, const bool is_down) override; 56 void UserAbortEvent() override; 57 bool IsConfUiActive() override; 58 59 private: 60 explicit HostServer( 61 cuttlefish::HostModeCtrl& host_mode_ctrl, 62 cuttlefish::ScreenConnectorFrameRenderer& screen_connector); 63 HostServer() = delete; 64 65 /** 66 * basic prompt flow: 67 * (1) Without preemption 68 * send "kStart" with confirmation message 69 * wait kCliAck from the host service with the echoed command 70 * wait the confirmation/cancellation (or perhaps reset?) 71 * send kStop 72 * wait kCliAck from the host service with the echoed command 73 * 74 * (2) With preemption (e.g.) 75 * send "kStart" with confirmation message 76 * wait kCliAck from the host service with the echoed command 77 * wait the confirmation/cancellation (or perhaps reset?) 78 * send kSuspend // when HAL is preempted 79 * send kRestore // when HAL resumes 80 * send kStop 81 * 82 * From the host end, it is a close-to-Mealy FSM. 83 * There are four states S = {init, session, wait_ack, suspended} 84 * 85 * 'session' means in a confirmation session. 'wait_ack' means 86 * server sends the confirmation and waiting "stop" command from HAL 87 * 'suspended' means the HAL service is preemptied. So, the host 88 * should render the Android guest frames but keep the confirmation 89 * UI session and frame 90 * 91 * The inputs are I = {u, g}. 'u' is the user input from webRTC 92 * clients. Note that the host service serialized the concurrent user 93 * inputs from multiple clients. 'g' is the command from the HAL service 94 * 95 * The transition rules: 96 * (S, I) --> (S, O) where O is the output 97 * 98 * init, g(start) --> session, set Conf UI mode, render a frame 99 * session, u(cancel/confirm) --> waitstop, send the result to HAL 100 * session, g(suspend) --> suspend, create a saved session 101 * session, g(abort) --> init, clear saved frame 102 * waitstop, g(stop) --> init, clear saved frame 103 * waitstop, g(suspend) --> suspend, no need to save the session 104 * waitstop, g(abort) --> init, clear saved frame 105 * suspend, g(restore) --> return to the saved state, restore if there's a 106 * saved session 107 * suspend, g(abort) --> init, clear saved frame 108 * 109 * For now, we did not yet implement suspend or abort. 110 * 111 */ 112 [[noreturn]] void MainLoop(); 113 void HalCmdFetcherLoop(); 114 115 SharedFD EstablishHalConnection(); 116 117 std::shared_ptr<Session> CreateSession(const std::string& session_name); 118 void SendUserSelection(std::unique_ptr<ConfUiMessage>& input); 119 120 void Transition(std::unique_ptr<ConfUiMessage>& input_ptr); GetCurrentSessionId()121 std::string GetCurrentSessionId() { 122 if (curr_session_) { 123 return curr_session_->GetId(); 124 } 125 return SESSION_ANY; 126 } 127 GetCurrentState()128 std::string GetCurrentState() { 129 if (!curr_session_) { 130 return {"kInvalid"}; 131 } 132 return ToString(curr_session_->GetState()); 133 } 134 135 const std::uint32_t display_num_; 136 HostModeCtrl& host_mode_ctrl_; 137 ScreenConnectorFrameRenderer& screen_connector_; 138 139 std::string input_socket_path_; 140 int hal_vsock_port_; 141 142 std::shared_ptr<Session> curr_session_; 143 144 SharedFD guest_hal_socket_; 145 // ACCEPTED fd on guest_hal_socket_ 146 SharedFD hal_cli_socket_; 147 148 using Multiplexer = 149 Multiplexer<std::unique_ptr<ConfUiMessage>, 150 ThreadSafeQueue<std::unique_ptr<ConfUiMessage>>>; 151 /* 152 * Multiplexer has N queues. When pop(), it is going to sleep until 153 * there's at least one item in at least one queue. The lower the Q 154 * index is, the higher the priority is. 155 * 156 * For HostServer, we have a queue for the user input events, and 157 * another for hal cmd/msg queues 158 */ 159 Multiplexer input_multiplexer_; 160 int hal_cmd_q_id_; // Q id in input_multiplexer_ 161 int user_input_evt_q_id_; // Q id in input_multiplexer_ 162 163 std::thread main_loop_thread_; 164 std::thread hal_input_fetcher_thread_; 165 166 std::mutex socket_flag_mtx_; 167 std::condition_variable socket_flag_cv_; 168 bool is_socket_ok_; 169 }; 170 171 } // end of namespace confui 172 } // end of namespace cuttlefish 173