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