blob: 03ca4cc79d7146d0635f2873dc7112f76289d500 [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.
#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