You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
270 lines
9.1 KiB
270 lines
9.1 KiB
/*
|
|
* 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.
|
|
*/
|
|
|
|
#include "host/libs/confui/session.h"
|
|
|
|
namespace cuttlefish {
|
|
namespace confui {
|
|
|
|
Session::Session(const std::string& session_id, const std::uint32_t display_num,
|
|
ConfUiRenderer& host_renderer, HostModeCtrl& host_mode_ctrl,
|
|
ScreenConnectorFrameRenderer& screen_connector,
|
|
const std::string& locale)
|
|
: session_id_{session_id},
|
|
display_num_{display_num},
|
|
renderer_{host_renderer},
|
|
host_mode_ctrl_{host_mode_ctrl},
|
|
screen_connector_{screen_connector},
|
|
locale_{locale},
|
|
state_{MainLoopState::kInit},
|
|
saved_state_{MainLoopState::kInit} {}
|
|
|
|
bool Session::IsConfUiActive() const {
|
|
if (state_ == MainLoopState::kInSession ||
|
|
state_ == MainLoopState::kWaitStop) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Session::RenderDialog(const std::string& msg, const std::string& locale) {
|
|
auto [teeui_frame, is_success] = renderer_.RenderRawFrame(msg, locale);
|
|
if (!is_success) {
|
|
return false;
|
|
}
|
|
prompt_ = msg;
|
|
locale_ = locale;
|
|
|
|
ConfUiLog(DEBUG) << "actually trying to render the frame"
|
|
<< thread::GetName();
|
|
auto raw_frame = reinterpret_cast<std::uint8_t*>(teeui_frame.data());
|
|
return screen_connector_.RenderConfirmationUi(display_num_, raw_frame);
|
|
}
|
|
|
|
bool Session::IsSuspended() const {
|
|
return (state_ == MainLoopState::kSuspended);
|
|
}
|
|
|
|
MainLoopState Session::Transition(const bool is_user_input, SharedFD& hal_cli,
|
|
const FsmInput fsm_input,
|
|
const std::string& additional_info) {
|
|
switch (state_) {
|
|
case MainLoopState::kInit: {
|
|
HandleInit(is_user_input, hal_cli, fsm_input, additional_info);
|
|
} break;
|
|
case MainLoopState::kInSession: {
|
|
HandleInSession(is_user_input, hal_cli, fsm_input);
|
|
} break;
|
|
case MainLoopState::kWaitStop: {
|
|
if (is_user_input) {
|
|
ConfUiLog(DEBUG) << "User input ignored" << ToString(fsm_input) << " : "
|
|
<< additional_info << "at state" << ToString(state_);
|
|
}
|
|
HandleWaitStop(is_user_input, hal_cli, fsm_input);
|
|
} break;
|
|
default:
|
|
// host service explicitly calls restore and suspend
|
|
ConfUiLog(FATAL) << "Must not be in the state of" << ToString(state_);
|
|
break;
|
|
}
|
|
return state_;
|
|
};
|
|
|
|
bool Session::Suspend(SharedFD hal_cli) {
|
|
if (state_ == MainLoopState::kInit) {
|
|
// HAL sent wrong command
|
|
ConfUiLog(FATAL)
|
|
<< "HAL sent wrong command, suspend, when the session is in kIinit";
|
|
return false;
|
|
}
|
|
if (state_ == MainLoopState::kSuspended) {
|
|
ConfUiLog(DEBUG) << "Already kSuspended state";
|
|
return false;
|
|
}
|
|
saved_state_ = state_;
|
|
state_ = MainLoopState::kSuspended;
|
|
host_mode_ctrl_.SetMode(HostModeCtrl::ModeType::kAndroidMode);
|
|
if (!packet::SendAck(hal_cli, session_id_, /*is success*/ true,
|
|
"suspended")) {
|
|
ConfUiLog(FATAL) << "I/O error";
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool Session::Restore(SharedFD hal_cli) {
|
|
if (state_ == MainLoopState::kInit) {
|
|
// HAL sent wrong command
|
|
ConfUiLog(FATAL)
|
|
<< "HAL sent wrong command, restore, when the session is in kIinit";
|
|
return false;
|
|
}
|
|
|
|
if (state_ != MainLoopState::kSuspended) {
|
|
ConfUiLog(DEBUG) << "Already Restored to state " + ToString(state_);
|
|
return false;
|
|
}
|
|
host_mode_ctrl_.SetMode(HostModeCtrl::ModeType::kConfUI_Mode);
|
|
if (!RenderDialog(prompt_, locale_)) {
|
|
// the confirmation UI is driven by a user app, not running from the start
|
|
// automatically so that means webRTC/vnc should have been set up
|
|
ConfUiLog(ERROR) << "Dialog is not rendered. However, it should."
|
|
<< "No webRTC can't initiate any confirmation UI.";
|
|
if (!packet::SendAck(hal_cli, session_id_, false,
|
|
"render failed in restore")) {
|
|
ConfUiLog(FATAL) << "Rendering failed in restore, and ack failed in I/O";
|
|
}
|
|
state_ = MainLoopState::kInit;
|
|
return false;
|
|
}
|
|
if (!packet::SendAck(hal_cli, session_id_, true, "restored")) {
|
|
ConfUiLog(FATAL) << "Ack to restore failed in I/O";
|
|
}
|
|
state_ = saved_state_;
|
|
saved_state_ = MainLoopState::kInit;
|
|
return true;
|
|
}
|
|
|
|
bool Session::Kill(SharedFD hal_cli, const std::string& response_msg) {
|
|
state_ = MainLoopState::kAwaitCleanup;
|
|
saved_state_ = MainLoopState::kInvalid;
|
|
if (!packet::SendAck(hal_cli, session_id_, true, response_msg)) {
|
|
ConfUiLog(FATAL) << "I/O error in ack to Abort";
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void Session::CleanUp() {
|
|
if (state_ != MainLoopState::kAwaitCleanup) {
|
|
ConfUiLog(FATAL) << "Clean up a session only when in kAwaitCleanup";
|
|
}
|
|
// common action done when the state is back to init state
|
|
host_mode_ctrl_.SetMode(HostModeCtrl::ModeType::kAndroidMode);
|
|
}
|
|
|
|
void Session::ReportErrorToHal(SharedFD hal_cli, const std::string& msg) {
|
|
// reset the session -- destroy it & recreate it with the same
|
|
// session id
|
|
state_ = MainLoopState::kAwaitCleanup;
|
|
if (!packet::SendAck(hal_cli, session_id_, false, msg)) {
|
|
ConfUiLog(FATAL) << "I/O error in sending ack to report rendering failure";
|
|
}
|
|
return;
|
|
}
|
|
|
|
bool Session::Abort(SharedFD hal_cli) { return Kill(hal_cli, "aborted"); }
|
|
|
|
void Session::HandleInit(const bool is_user_input, SharedFD hal_cli,
|
|
const FsmInput fsm_input,
|
|
const std::string& additional_info) {
|
|
using namespace cuttlefish::confui::packet;
|
|
if (is_user_input) {
|
|
// ignore user input
|
|
state_ = MainLoopState::kInit;
|
|
return;
|
|
}
|
|
|
|
ConfUiLog(DEBUG) << ToString(fsm_input) << "is handled in HandleInit";
|
|
if (fsm_input != FsmInput::kHalStart) {
|
|
ConfUiLog(ERROR) << "invalid cmd for Init State:" << ToString(fsm_input);
|
|
// reset the session -- destroy it & recreate it with the same
|
|
// session id
|
|
ReportErrorToHal(hal_cli, "wrong hal command");
|
|
return;
|
|
}
|
|
|
|
// Start Session
|
|
ConfUiLog(DEBUG) << "Sending ack to hal_cli: "
|
|
<< Enum2Base(ConfUiCmd::kCliAck);
|
|
host_mode_ctrl_.SetMode(HostModeCtrl::ModeType::kConfUI_Mode);
|
|
auto confirmation_msg = additional_info;
|
|
if (!RenderDialog(confirmation_msg, locale_)) {
|
|
// the confirmation UI is driven by a user app, not running from the start
|
|
// automatically so that means webRTC/vnc should have been set up
|
|
ConfUiLog(ERROR) << "Dialog is not rendered. However, it should."
|
|
<< "No webRTC can't initiate any confirmation UI.";
|
|
ReportErrorToHal(hal_cli, "rendering failed");
|
|
return;
|
|
}
|
|
if (!packet::SendAck(hal_cli, session_id_, true, "started")) {
|
|
ConfUiLog(FATAL) << "Ack to kStart failed in I/O";
|
|
}
|
|
state_ = MainLoopState::kInSession;
|
|
return;
|
|
}
|
|
|
|
void Session::HandleInSession(const bool is_user_input, SharedFD hal_cli,
|
|
const FsmInput fsm_input) {
|
|
if (!is_user_input) {
|
|
ConfUiLog(FATAL) << "cmd" << ToString(fsm_input)
|
|
<< "should not be handled in HandleInSession";
|
|
ReportErrorToHal(hal_cli, "wrong hal command");
|
|
return;
|
|
}
|
|
|
|
// send to hal_cli either confirm or cancel
|
|
if (fsm_input != FsmInput::kUserConfirm &&
|
|
fsm_input != FsmInput::kUserCancel) {
|
|
/*
|
|
* TODO(kwstephenkim@google.com): change here when other user inputs must
|
|
* be handled
|
|
*
|
|
*/
|
|
if (!packet::SendAck(hal_cli, session_id_, true,
|
|
"invalid user input error")) {
|
|
// note that input is what we control in memory
|
|
ConfUiCheck(false) << "Input must be either confirm or cancel for now.";
|
|
}
|
|
return;
|
|
}
|
|
|
|
ConfUiLog(DEBUG) << "In HandlieInSession, session" << session_id_
|
|
<< "is sending the user input" << ToString(fsm_input);
|
|
auto selection = UserResponse::kConfirm;
|
|
if (fsm_input == FsmInput::kUserCancel) {
|
|
selection = UserResponse::kCancel;
|
|
}
|
|
if (!packet::SendResponse(hal_cli, session_id_, selection)) {
|
|
ConfUiLog(FATAL) << "I/O error in sending user response to HAL";
|
|
}
|
|
state_ = MainLoopState::kWaitStop;
|
|
return;
|
|
}
|
|
|
|
void Session::HandleWaitStop(const bool is_user_input, SharedFD hal_cli,
|
|
const FsmInput fsm_input) {
|
|
using namespace cuttlefish::confui::packet;
|
|
|
|
if (is_user_input) {
|
|
// ignore user input
|
|
state_ = MainLoopState::kWaitStop;
|
|
return;
|
|
}
|
|
if (fsm_input == FsmInput::kHalStop) {
|
|
ConfUiLog(DEBUG) << "Handling Abort in kWaitStop.";
|
|
Kill(hal_cli, "stopped");
|
|
return;
|
|
}
|
|
ConfUiLog(FATAL) << "In WaitStop, received wrong HAL command "
|
|
<< ToString(fsm_input);
|
|
state_ = MainLoopState::kAwaitCleanup;
|
|
return;
|
|
}
|
|
|
|
} // end of namespace confui
|
|
} // end of namespace cuttlefish
|