/* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include #include #include #include #include #include #include #include #include "common/libs/concurrency/multiplexer.h" #include "common/libs/concurrency/semaphore.h" #include "common/libs/confui/confui.h" #include "common/libs/fs/shared_fd.h" #include "host/commands/kernel_log_monitor/utils.h" #include "host/libs/config/logging.h" #include "host/libs/confui/host_mode_ctrl.h" #include "host/libs/confui/host_renderer.h" #include "host/libs/confui/host_virtual_input.h" #include "host/libs/confui/server_common.h" #include "host/libs/confui/session.h" #include "host/libs/screen_connector/screen_connector.h" namespace cuttlefish { namespace confui { class HostServer : public HostVirtualInput { public: static HostServer& Get( HostModeCtrl& host_mode_ctrl, cuttlefish::ScreenConnectorFrameRenderer& screen_connector); void Start(); // start this server itself virtual ~HostServer() = default; // implement input interfaces. called by webRTC & vnc void PressConfirmButton(const bool is_down) override; void PressCancelButton(const bool is_down) override; bool IsConfUiActive() override; private: explicit HostServer( cuttlefish::HostModeCtrl& host_mode_ctrl, cuttlefish::ScreenConnectorFrameRenderer& screen_connector); HostServer() = delete; /** * basic prompt flow: * (1) Without preemption * send "kStart" with confirmation message * wait kCliAck from the host service with the echoed command * wait the confirmation/cancellation (or perhaps reset?) * send kStop * wait kCliAck from the host service with the echoed command * * (2) With preemption (e.g.) * send "kStart" with confirmation message * wait kCliAck from the host service with the echoed command * wait the confirmation/cancellation (or perhaps reset?) * send kSuspend // when HAL is preempted * send kRestore // when HAL resumes * send kStop * * From the host end, it is a close-to-Mealy FSM. * There are four states S = {init, session, wait_ack, suspended} * * 'session' means in a confirmation session. 'wait_ack' means * server sends the confirmation and waiting "stop" command from HAL * 'suspended' means the HAL service is preemptied. So, the host * should render the Android guest frames but keep the confirmation * UI session and frame * * The inputs are I = {u, g}. 'u' is the user input from vnc/webRTC * clients. Note that the host service serialized the concurrent user * inputs from multiple clients. 'g' is the command from the HAL service * * The transition rules: * (S, I) --> (S, O) where O is the output * * init, g(start) --> session, set Conf UI mode, render a frame * session, u(cancel/confirm) --> waitstop, send the result to HAL * session, g(suspend) --> suspend, create a saved session * session, g(abort) --> init, clear saved frame * waitstop, g(stop) --> init, clear saved frame * waitstop, g(suspend) --> suspend, no need to save the session * waitstop, g(abort) --> init, clear saved frame * suspend, g(restore) --> return to the saved state, restore if there's a * saved session * suspend, g(abort) --> init, clear saved frame * * For now, we did not yet implement suspend or abort. * */ [[noreturn]] void MainLoop(); void HalCmdFetcherLoop(); SharedFD EstablishHalConnection(); // failed to start dialog, etc // basically, will reset the session, so start from the beginning in the same // session void ResetOnCommandFailure(); // note: the picked session will be removed from session_map_ std::unique_ptr GetSession(const std::string& session_id) { if (session_map_.find(session_id) == session_map_.end()) { return nullptr; } std::unique_ptr temp = std::move(session_map_[session_id]); session_map_.erase(session_id); return temp; } std::string GetCurrentSessionId() { if (curr_session_) { return curr_session_->GetId(); } return SESSION_ANY; } std::string GetCurrentState() { if (!curr_session_) { return {"kInvalid"}; } return ToString(curr_session_->GetState()); } std::unique_ptr ComputeCurrentSession(const std::string& session_id); bool SendUserSelection(UserResponse::type selection); const std::uint32_t display_num_; HostModeCtrl& host_mode_ctrl_; ScreenConnectorFrameRenderer& screen_connector_; // this member creates a raw frame ConfUiRenderer renderer_; std::string input_socket_path_; std::string hal_socket_path_; // session id to Session object map, for those that are suspended std::unordered_map> session_map_; // curr_session_ doesn't belong to session_map_ std::unique_ptr curr_session_; SharedFD guest_hal_socket_; // ACCEPTED fd on guest_hal_socket_ SharedFD hal_cli_socket_; std::mutex input_socket_mtx_; /* * Multiplexer has N queues. When pop(), it is going to sleep until * there's at least one item in at least one queue. The lower the Q * index is, the higher the priority is. * * For HostServer, we have a queue for the user input events, and * another for hal cmd/msg queues */ Multiplexer input_multiplexer_; int hal_cmd_q_id_; // Q id in input_multiplexer_ int user_input_evt_q_id_; // Q id in input_multiplexer_ std::thread main_loop_thread_; std::thread hal_input_fetcher_thread_; }; } // end of namespace confui } // end of namespace cuttlefish