274 lines
9.9 KiB
C++
274 lines
9.9 KiB
C++
//
|
|
// 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 "common/libs/confui/protocol.h"
|
|
|
|
#include <sstream>
|
|
#include <vector>
|
|
|
|
#include <android-base/strings.h>
|
|
|
|
#include "common/libs/confui/packet.h"
|
|
#include "common/libs/confui/utils.h"
|
|
#include "common/libs/fs/shared_buf.h"
|
|
|
|
namespace cuttlefish {
|
|
namespace confui {
|
|
namespace {
|
|
// default implementation of ToConfUiMessage
|
|
template <ConfUiCmd C>
|
|
std::unique_ptr<ConfUiMessage> ToConfUiMessage(
|
|
const packet::ParsedPacket& message) {
|
|
return std::make_unique<ConfUiGenericMessage<C>>(message.session_id_);
|
|
}
|
|
|
|
// these are specialized, and defined below
|
|
template <>
|
|
std::unique_ptr<ConfUiMessage> ToConfUiMessage<ConfUiCmd::kCliAck>(
|
|
const packet::ParsedPacket& message);
|
|
template <>
|
|
std::unique_ptr<ConfUiMessage> ToConfUiMessage<ConfUiCmd::kStart>(
|
|
const packet::ParsedPacket& message);
|
|
template <>
|
|
std::unique_ptr<ConfUiMessage> ToConfUiMessage<ConfUiCmd::kUserInputEvent>(
|
|
const packet::ParsedPacket& message);
|
|
template <>
|
|
std::unique_ptr<ConfUiMessage> ToConfUiMessage<ConfUiCmd::kUserTouchEvent>(
|
|
const packet::ParsedPacket& message);
|
|
template <>
|
|
std::unique_ptr<ConfUiMessage> ToConfUiMessage<ConfUiCmd::kCliRespond>(
|
|
const packet::ParsedPacket& message);
|
|
|
|
std::unique_ptr<ConfUiMessage> ToConfUiMessage(
|
|
const packet::ParsedPacket& confui_packet) {
|
|
const auto confui_cmd = ToCmd(confui_packet.type_);
|
|
switch (confui_cmd) {
|
|
// customized ConfUiMessage
|
|
case ConfUiCmd::kStart:
|
|
return ToConfUiMessage<ConfUiCmd::kStart>(confui_packet);
|
|
case ConfUiCmd::kCliAck:
|
|
return ToConfUiMessage<ConfUiCmd::kCliAck>(confui_packet);
|
|
case ConfUiCmd::kCliRespond:
|
|
return ToConfUiMessage<ConfUiCmd::kCliRespond>(confui_packet);
|
|
case ConfUiCmd::kUserInputEvent:
|
|
return ToConfUiMessage<ConfUiCmd::kUserInputEvent>(confui_packet);
|
|
case ConfUiCmd::kUserTouchEvent:
|
|
return ToConfUiMessage<ConfUiCmd::kUserTouchEvent>(confui_packet);
|
|
// default ConfUiMessage with session & type only
|
|
case ConfUiCmd::kAbort:
|
|
return ToConfUiMessage<ConfUiCmd::kAbort>(confui_packet);
|
|
case ConfUiCmd::kStop:
|
|
return ToConfUiMessage<ConfUiCmd::kStop>(confui_packet);
|
|
// these are errors
|
|
case ConfUiCmd::kUnknown:
|
|
default:
|
|
ConfUiLog(ERROR) << "ConfUiCmd value is not good for ToConfUiMessage: "
|
|
<< ToString(confui_cmd);
|
|
break;
|
|
}
|
|
return {nullptr};
|
|
}
|
|
} // end of unnamed namespace
|
|
|
|
std::string ToString(const ConfUiMessage& msg) { return msg.ToString(); }
|
|
|
|
std::unique_ptr<ConfUiMessage> RecvConfUiMsg(SharedFD fd) {
|
|
if (!fd->IsOpen()) {
|
|
ConfUiLog(ERROR) << "file, socket, etc, is not open to read";
|
|
return {nullptr};
|
|
}
|
|
auto confui_packet_opt = packet::ReadPayload(fd);
|
|
if (!confui_packet_opt) {
|
|
ConfUiLog(ERROR) << "ReadPayload returns but with std::nullptr";
|
|
return {nullptr};
|
|
}
|
|
|
|
auto confui_packet = confui_packet_opt.value();
|
|
return ToConfUiMessage(confui_packet);
|
|
}
|
|
|
|
std::unique_ptr<ConfUiMessage> RecvConfUiMsg(const std::string& session_id,
|
|
SharedFD fd) {
|
|
auto conf_ui_msg = RecvConfUiMsg(fd);
|
|
if (!conf_ui_msg) {
|
|
return {nullptr};
|
|
}
|
|
auto recv_session_id = conf_ui_msg->GetSessionId();
|
|
if (session_id != recv_session_id) {
|
|
ConfUiLog(ERROR) << "Received Session ID (" << recv_session_id
|
|
<< ") is not the expected one (" << session_id << ")";
|
|
return {nullptr};
|
|
}
|
|
return conf_ui_msg;
|
|
}
|
|
|
|
bool SendAbortCmd(SharedFD fd, const std::string& session_id) {
|
|
ConfUiGenericMessage<ConfUiCmd::kAbort> confui_msg{session_id};
|
|
return confui_msg.SendOver(fd);
|
|
}
|
|
|
|
bool SendStopCmd(SharedFD fd, const std::string& session_id) {
|
|
ConfUiGenericMessage<ConfUiCmd::kStop> confui_msg{session_id};
|
|
return confui_msg.SendOver(fd);
|
|
}
|
|
|
|
bool SendAck(SharedFD fd, const std::string& session_id, const bool is_success,
|
|
const std::string& status_message) {
|
|
ConfUiAckMessage confui_msg{session_id, is_success, status_message};
|
|
return confui_msg.SendOver(fd);
|
|
}
|
|
|
|
bool SendResponse(SharedFD fd, const std::string& session_id,
|
|
const UserResponse::type& plain_selection,
|
|
const std::vector<std::uint8_t>& signed_response,
|
|
const std::vector<std::uint8_t>& message) {
|
|
ConfUiCliResponseMessage confui_msg{session_id, plain_selection,
|
|
signed_response, message};
|
|
return confui_msg.SendOver(fd);
|
|
}
|
|
|
|
bool SendStartCmd(SharedFD fd, const std::string& session_id,
|
|
const std::string& prompt_text,
|
|
const std::vector<std::uint8_t>& extra_data,
|
|
const std::string& locale,
|
|
const std::vector<teeui::UIOption>& ui_opts) {
|
|
ConfUiStartMessage confui_msg{session_id, prompt_text, extra_data, locale,
|
|
ui_opts};
|
|
return confui_msg.SendOver(fd);
|
|
}
|
|
|
|
// this is only for deliverSecureInputEvent
|
|
bool SendUserSelection(SharedFD fd, const std::string& session_id,
|
|
const UserResponse::type& confirm_cancel) {
|
|
ConfUiUserSelectionMessage confui_msg{session_id, confirm_cancel};
|
|
return confui_msg.SendOver(fd);
|
|
}
|
|
|
|
// specialized ToConfUiMessage()
|
|
namespace {
|
|
template <>
|
|
std::unique_ptr<ConfUiMessage> ToConfUiMessage<ConfUiCmd::kCliAck>(
|
|
const packet::ParsedPacket& message) {
|
|
auto type = ToCmd(message.type_);
|
|
auto& contents = message.additional_info_;
|
|
if (type != ConfUiCmd::kCliAck) {
|
|
ConfUiLog(ERROR) << "Received cmd is not ack but " << ToString(type);
|
|
return {nullptr};
|
|
}
|
|
|
|
if (contents.size() != 2) {
|
|
ConfUiLog(ERROR)
|
|
<< "Ack message should only have pass/fail and a status message";
|
|
return {nullptr};
|
|
}
|
|
|
|
const std::string success_str(contents[0].begin(), contents[0].end());
|
|
const bool is_success = (success_str == "success");
|
|
const std::string status_message(contents[1].begin(), contents[1].end());
|
|
return std::make_unique<ConfUiAckMessage>(message.session_id_, is_success,
|
|
status_message);
|
|
}
|
|
|
|
template <>
|
|
std::unique_ptr<ConfUiMessage> ToConfUiMessage<ConfUiCmd::kStart>(
|
|
const packet::ParsedPacket& message) {
|
|
/*
|
|
* additional_info_[0]: prompt text
|
|
* additional_info_[1]: extra data
|
|
* additional_info_[2]: locale
|
|
* additional_info_[3]: UIOptions
|
|
*
|
|
*/
|
|
if (message.additional_info_.size() < 3) {
|
|
ConfUiLog(ERROR) << "ConfUiMessage for kStart is ill-formatted: "
|
|
<< packet::ToString(message);
|
|
return {nullptr};
|
|
}
|
|
std::vector<teeui::UIOption> ui_opts;
|
|
bool has_ui_option = (message.additional_info_.size() == 4) &&
|
|
!(message.additional_info_[3].empty());
|
|
if (has_ui_option) {
|
|
std::string ui_opts_string{message.additional_info_[3].begin(),
|
|
message.additional_info_[3].end()};
|
|
auto tokens = android::base::Split(ui_opts_string, ",");
|
|
for (auto token : tokens) {
|
|
auto ui_opt_optional = ToUiOption(token);
|
|
if (!ui_opt_optional) {
|
|
ConfUiLog(ERROR) << "Wrong UiOption String : " << token;
|
|
return {nullptr};
|
|
}
|
|
ui_opts.emplace_back(ui_opt_optional.value());
|
|
}
|
|
}
|
|
auto sm = std::make_unique<ConfUiStartMessage>(
|
|
message.session_id_,
|
|
std::string(message.additional_info_[0].begin(),
|
|
message.additional_info_[0].end()),
|
|
message.additional_info_[1],
|
|
std::string(message.additional_info_[2].begin(),
|
|
message.additional_info_[2].end()),
|
|
ui_opts);
|
|
return sm;
|
|
}
|
|
|
|
template <>
|
|
std::unique_ptr<ConfUiMessage> ToConfUiMessage<ConfUiCmd::kUserInputEvent>(
|
|
const packet::ParsedPacket& message) {
|
|
if (message.additional_info_.size() < 1) {
|
|
ConfUiLog(ERROR)
|
|
<< "kUserInputEvent message should have at least one additional_info_";
|
|
return {nullptr};
|
|
}
|
|
auto response = std::string{message.additional_info_[0].begin(),
|
|
message.additional_info_[0].end()};
|
|
return std::make_unique<ConfUiUserSelectionMessage>(message.session_id_,
|
|
response);
|
|
}
|
|
|
|
template <>
|
|
std::unique_ptr<ConfUiMessage> ToConfUiMessage<ConfUiCmd::kUserTouchEvent>(
|
|
const packet::ParsedPacket& message) {
|
|
if (message.additional_info_.size() < 2) {
|
|
ConfUiLog(ERROR)
|
|
<< "kUserTouchEvent message should have at least two additional_info_";
|
|
return {nullptr};
|
|
}
|
|
auto x = std::string(message.additional_info_[0].begin(),
|
|
message.additional_info_[0].end());
|
|
auto y = std::string(message.additional_info_[1].begin(),
|
|
message.additional_info_[1].end());
|
|
return std::make_unique<ConfUiUserTouchMessage>(message.session_id_,
|
|
std::stoi(x), std::stoi(y));
|
|
}
|
|
|
|
template <>
|
|
std::unique_ptr<ConfUiMessage> ToConfUiMessage<ConfUiCmd::kCliRespond>(
|
|
const packet::ParsedPacket& message) {
|
|
if (message.additional_info_.size() < 3) {
|
|
ConfUiLog(ERROR)
|
|
<< "kCliRespond message should have at least two additional info";
|
|
return {nullptr};
|
|
}
|
|
auto response = std::string{message.additional_info_[0].begin(),
|
|
message.additional_info_[0].end()};
|
|
auto sign = message.additional_info_[1];
|
|
auto msg = message.additional_info_[2];
|
|
return std::make_unique<ConfUiCliResponseMessage>(message.session_id_,
|
|
response, sign, msg);
|
|
}
|
|
} // end of unnamed namespace
|
|
} // end of namespace confui
|
|
} // end of namespace cuttlefish
|