blob: 904af339dcbf3075006be108801c9f5e44005c4a [file] [log] [blame]
/*
* 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 <atomic>
#include <cstdint>
#include <memory>
#include <mutex>
#include <string>
#include <thread>
#include <unordered_map>
#include <vector>
#include <android-base/logging.h>
#include <teeui/utils.h>
#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_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() {}
// implement input interfaces. called by webRTC
void TouchEvent(const int x, const int y, const bool is_down) override;
void UserAbortEvent() 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 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();
std::shared_ptr<Session> CreateSession(const std::string& session_name);
void SendUserSelection(std::unique_ptr<ConfUiMessage>& input);
void Transition(std::unique_ptr<ConfUiMessage>& input_ptr);
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());
}
const std::uint32_t display_num_;
HostModeCtrl& host_mode_ctrl_;
ScreenConnectorFrameRenderer& screen_connector_;
std::string input_socket_path_;
int hal_vsock_port_;
std::shared_ptr<Session> curr_session_;
SharedFD guest_hal_socket_;
// ACCEPTED fd on guest_hal_socket_
SharedFD hal_cli_socket_;
using Multiplexer =
Multiplexer<std::unique_ptr<ConfUiMessage>,
ThreadSafeQueue<std::unique_ptr<ConfUiMessage>>>;
/*
* 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_;
std::mutex socket_flag_mtx_;
std::condition_variable socket_flag_cv_;
bool is_socket_ok_;
};
} // end of namespace confui
} // end of namespace cuttlefish