• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "host/libs/confui/host_server.h"
18 
19 #include <chrono>
20 #include <functional>
21 #include <optional>
22 #include <tuple>
23 
24 #include "common/libs/confui/confui.h"
25 #include "host/libs/config/cuttlefish_config.h"
26 #include "host/libs/confui/host_utils.h"
27 
28 namespace cuttlefish {
29 namespace confui {
CuttlefishConfigDefaultInstance()30 static auto CuttlefishConfigDefaultInstance() {
31   auto config = cuttlefish::CuttlefishConfig::Get();
32   CHECK(config) << "Config must not be null";
33   return config->ForDefaultInstance();
34 }
35 
HalGuestSocketPath()36 static std::string HalGuestSocketPath() {
37   return CuttlefishConfigDefaultInstance().confui_hal_guest_socket_path();
38 }
39 
Get(HostModeCtrl & host_mode_ctrl,cuttlefish::ScreenConnectorFrameRenderer & screen_connector)40 HostServer& HostServer::Get(
41     HostModeCtrl& host_mode_ctrl,
42     cuttlefish::ScreenConnectorFrameRenderer& screen_connector) {
43   static HostServer host_server{host_mode_ctrl, screen_connector};
44   return host_server;
45 }
46 
HostServer(cuttlefish::HostModeCtrl & host_mode_ctrl,cuttlefish::ScreenConnectorFrameRenderer & screen_connector)47 HostServer::HostServer(
48     cuttlefish::HostModeCtrl& host_mode_ctrl,
49     cuttlefish::ScreenConnectorFrameRenderer& screen_connector)
50     : display_num_(0),
51       host_mode_ctrl_(host_mode_ctrl),
52       screen_connector_{screen_connector},
53       renderer_(display_num_),
54       hal_socket_path_(HalGuestSocketPath()),
55       input_multiplexer_{/* max n_elems */ 20, /* n_Qs */ 2} {
56   hal_cmd_q_id_ = input_multiplexer_.GetNewQueueId();         // return 0
57   user_input_evt_q_id_ = input_multiplexer_.GetNewQueueId();  // return 1
58 }
59 
Start()60 void HostServer::Start() {
61   guest_hal_socket_ = cuttlefish::SharedFD::SocketLocalServer(
62       hal_socket_path_, false, SOCK_STREAM, 0666);
63   if (!guest_hal_socket_->IsOpen()) {
64     ConfUiLog(FATAL) << "Confirmation UI host service mandates a server socket"
65                      << "to which the guest HAL to connect.";
66     return;
67   }
68   auto hal_cmd_fetching = [this]() { this->HalCmdFetcherLoop(); };
69   auto main = [this]() { this->MainLoop(); };
70   hal_input_fetcher_thread_ =
71       thread::RunThread("HalInputLoop", hal_cmd_fetching);
72   main_loop_thread_ = thread::RunThread("MainLoop", main);
73   ConfUiLog(DEBUG) << "configured internal socket based input.";
74   return;
75 }
76 
HalCmdFetcherLoop()77 void HostServer::HalCmdFetcherLoop() {
78   hal_cli_socket_ = EstablishHalConnection();
79   if (!hal_cli_socket_->IsOpen()) {
80     ConfUiLog(FATAL)
81         << "Confirmation UI host service mandates connection with HAL.";
82     return;
83   }
84   while (true) {
85     auto opted_msg = RecvConfUiMsg(hal_cli_socket_);
86     if (!opted_msg) {
87       ConfUiLog(ERROR) << "Error in RecvConfUiMsg from HAL";
88       continue;
89     }
90     auto input = std::move(opted_msg.value());
91     input_multiplexer_.Push(hal_cmd_q_id_, std::move(input));
92   }
93 }
94 
SendUserSelection(UserResponse::type selection)95 bool HostServer::SendUserSelection(UserResponse::type selection) {
96   if (!curr_session_) {
97     ConfUiLog(FATAL) << "Current session must not be null";
98     return false;
99   }
100   if (curr_session_->GetState() != MainLoopState::kInSession) {
101     // ignore
102     return true;
103   }
104 
105   std::lock_guard<std::mutex> lock(input_socket_mtx_);
106   if (selection != UserResponse::kConfirm &&
107       selection != UserResponse::kCancel) {
108     ConfUiLog(FATAL) << selection << " must be either" << UserResponse::kConfirm
109                      << "or" << UserResponse::kCancel;
110     return false;  // not reaching here
111   }
112 
113   ConfUiMessage input{GetCurrentSessionId(),
114                       ToString(ConfUiCmd::kUserInputEvent), selection};
115 
116   input_multiplexer_.Push(user_input_evt_q_id_, std::move(input));
117   return true;
118 }
119 
PressConfirmButton(const bool is_down)120 void HostServer::PressConfirmButton(const bool is_down) {
121   if (!is_down) {
122     return;
123   }
124   // shared by N vnc/webRTC clients
125   SendUserSelection(UserResponse::kConfirm);
126 }
127 
PressCancelButton(const bool is_down)128 void HostServer::PressCancelButton(const bool is_down) {
129   if (!is_down) {
130     return;
131   }
132   // shared by N vnc/webRTC clients
133   SendUserSelection(UserResponse::kCancel);
134 }
135 
IsConfUiActive()136 bool HostServer::IsConfUiActive() {
137   if (!curr_session_) {
138     return false;
139   }
140   return curr_session_->IsConfUiActive();
141 }
142 
EstablishHalConnection()143 SharedFD HostServer::EstablishHalConnection() {
144   ConfUiLog(DEBUG) << "Waiting hal accepting";
145   auto new_cli = SharedFD::Accept(*guest_hal_socket_);
146   ConfUiLog(DEBUG) << "hal client accepted";
147   return new_cli;
148 }
149 
ComputeCurrentSession(const std::string & session_id)150 std::unique_ptr<Session> HostServer::ComputeCurrentSession(
151     const std::string& session_id) {
152   if (curr_session_ && (GetCurrentSessionId() != session_id)) {
153     ConfUiLog(FATAL) << curr_session_->GetId() << " is active and in the"
154                      << GetCurrentState() << "but HAL sends command to"
155                      << session_id;
156   }
157   if (curr_session_) {
158     return std::move(curr_session_);
159   }
160 
161   // pick up a new session, or create one
162   auto result = GetSession(session_id);
163   if (result) {
164     return std::move(result);
165   }
166 
167   auto raw_ptr = new Session(session_id, display_num_, renderer_,
168                              host_mode_ctrl_, screen_connector_);
169   result = std::unique_ptr<Session>(raw_ptr);
170   // note that the new session is directly going to curr_session_
171   // when it is suspended, it will be moved to session_map_
172   return std::move(result);
173 }
174 
175 // read the comments in the header file
MainLoop()176 [[noreturn]] void HostServer::MainLoop() {
177   while (true) {
178     // this gets one input from either queue:
179     // from HAL or from all webrtc/vnc clients
180     // if no input, sleep until there is
181     const auto input = input_multiplexer_.Pop();
182     const auto& [session_id, cmd_str, additional_info] = input;
183 
184     // take input for the Finite States Machine below
185     const ConfUiCmd cmd = ToCmd(cmd_str);
186     const bool is_user_input = (cmd == ConfUiCmd::kUserInputEvent);
187     std::string src = is_user_input ? "input" : "hal";
188 
189     ConfUiLog(DEBUG) << "In Session" << GetCurrentSessionId() << ","
190                      << "in state" << GetCurrentState() << ","
191                      << "received input from" << src << "cmd =" << cmd_str
192                      << "and additional_info =" << additional_info
193                      << "going to session" << session_id;
194 
195     FsmInput fsm_input = ToFsmInput(input);
196 
197     if (is_user_input && !curr_session_) {
198       // discard the input, there's no session to take it yet
199       // actually, no confirmation UI screen is available
200       ConfUiLog(DEBUG) << "Took user input but no active session is available.";
201       continue;
202     }
203 
204     /**
205      * if the curr_session_ is null, create one
206      * if the curr_session_ is not null but the session id doesn't match,
207      * something is wrong. Confirmation UI doesn't allow preemption by
208      * another confirmation UI session back to back. When it's preempted,
209      * HAL must send "kSuspend"
210      *
211      */
212     curr_session_ = ComputeCurrentSession(session_id);
213     ConfUiLog(DEBUG) << "Host service picked up "
214                      << (curr_session_ ? curr_session_->GetId()
215                                        : "null session");
216     ConfUiLog(DEBUG) << "The state of current session is "
217                      << (curr_session_ ? ToString(curr_session_->GetState())
218                                        : "null session");
219 
220     if (is_user_input) {
221       curr_session_->Transition(is_user_input, hal_cli_socket_, fsm_input,
222                                 additional_info);
223     } else {
224       ConfUiCmd cmd = ToCmd(cmd_str);
225       switch (cmd) {
226         case ConfUiCmd::kSuspend:
227           curr_session_->Suspend(hal_cli_socket_);
228           break;
229         case ConfUiCmd::kRestore:
230           curr_session_->Restore(hal_cli_socket_);
231           break;
232         case ConfUiCmd::kAbort:
233           curr_session_->Abort(hal_cli_socket_);
234           break;
235         default:
236           curr_session_->Transition(is_user_input, hal_cli_socket_, fsm_input,
237                                     additional_info);
238           break;
239       }
240     }
241 
242     // check the session if it is inactive (e.g. init, suspended)
243     // and if it is done (transitioned to init from any other state)
244     if (curr_session_->IsSuspended()) {
245       session_map_[GetCurrentSessionId()] = std::move(curr_session_);
246       curr_session_ = nullptr;
247       continue;
248     }
249 
250     if (curr_session_->GetState() == MainLoopState::kAwaitCleanup) {
251       curr_session_->CleanUp();
252       curr_session_ = nullptr;
253     }
254     // otherwise, continue with keeping the curr_session_
255   }  // end of the infinite while loop
256 }
257 
258 }  // end of namespace confui
259 }  // end of namespace cuttlefish
260