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 <fruit/fruit.h> 30 #include <teeui/utils.h> 31 32 #include "common/libs/concurrency/multiplexer.h" 33 #include "common/libs/concurrency/semaphore.h" 34 #include "common/libs/confui/confui.h" 35 #include "common/libs/fs/shared_fd.h" 36 #include "host/commands/kernel_log_monitor/utils.h" 37 #include "host/libs/config/logging.h" 38 #include "host/libs/confui/host_mode_ctrl.h" 39 #include "host/libs/confui/host_renderer.h" 40 #include "host/libs/confui/server_common.h" 41 #include "host/libs/confui/session.h" 42 43 namespace cuttlefish { 44 namespace confui { 45 struct PipeConnectionPair { 46 SharedFD from_guest_; 47 SharedFD to_guest_; 48 }; 49 50 class HostServer { 51 public: 52 INJECT(HostServer(HostModeCtrl& host_mode_ctrl, ConfUiRenderer& host_renderer, 53 const PipeConnectionPair& fd_pair)); 54 55 void Start(); // start this server itself ~HostServer()56 virtual ~HostServer() {} 57 58 // implement input interfaces. called by webRTC 59 void TouchEvent(const int x, const int y, const bool is_down); 60 void UserAbortEvent(); 61 62 private: 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 bool IsVirtioConsoleOpen() const; 116 // If !IsVirtioConsoleOpen(), LOG(FATAL) and return false 117 bool CheckVirtioConsole(); 118 std::shared_ptr<Session> CreateSession(const std::string& session_name); 119 void SendUserSelection(std::unique_ptr<ConfUiMessage>& input); 120 121 void Transition(std::unique_ptr<ConfUiMessage>& input_ptr); GetCurrentSessionId()122 std::string GetCurrentSessionId() { 123 if (curr_session_) { 124 return curr_session_->GetId(); 125 } 126 return SESSION_ANY; 127 } 128 GetCurrentState()129 std::string GetCurrentState() { 130 if (!curr_session_) { 131 return {"kInvalid"}; 132 } 133 return ToString(curr_session_->GetState()); 134 } 135 136 const std::uint32_t display_num_; 137 ConfUiRenderer& host_renderer_; 138 HostModeCtrl& host_mode_ctrl_; 139 140 std::shared_ptr<Session> curr_session_; 141 142 SharedFD from_guest_fifo_fd_; 143 SharedFD to_guest_fifo_fd_; 144 145 using Multiplexer = 146 Multiplexer<std::unique_ptr<ConfUiMessage>, 147 ThreadSafeQueue<std::unique_ptr<ConfUiMessage>>>; 148 /* 149 * Multiplexer has N queues. When pop(), it is going to sleep until 150 * there's at least one item in at least one queue. The lower the Q 151 * index is, the higher the priority is. 152 * 153 * For HostServer, we have a queue for the user input events, and 154 * another for hal cmd/msg queues 155 */ 156 Multiplexer input_multiplexer_; 157 int hal_cmd_q_id_; // Q id in input_multiplexer_ 158 int user_input_evt_q_id_; // Q id in input_multiplexer_ 159 160 std::thread main_loop_thread_; 161 std::thread hal_input_fetcher_thread_; 162 }; 163 164 } // end of namespace confui 165 } // end of namespace cuttlefish 166