// // 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 #include #include #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 std::unique_ptr ToConfUiMessage( const packet::ParsedPacket& message) { return std::make_unique>(message.session_id_); } // these are specialized, and defined below template <> std::unique_ptr ToConfUiMessage( const packet::ParsedPacket& message); template <> std::unique_ptr ToConfUiMessage( const packet::ParsedPacket& message); template <> std::unique_ptr ToConfUiMessage( const packet::ParsedPacket& message); template <> std::unique_ptr ToConfUiMessage( const packet::ParsedPacket& message); template <> std::unique_ptr ToConfUiMessage( const packet::ParsedPacket& message); std::unique_ptr ToConfUiMessage( const packet::ParsedPacket& confui_packet) { const auto confui_cmd = ToCmd(confui_packet.type_); switch (confui_cmd) { // customized ConfUiMessage case ConfUiCmd::kStart: return ToConfUiMessage(confui_packet); case ConfUiCmd::kCliAck: return ToConfUiMessage(confui_packet); case ConfUiCmd::kCliRespond: return ToConfUiMessage(confui_packet); case ConfUiCmd::kUserInputEvent: return ToConfUiMessage(confui_packet); case ConfUiCmd::kUserTouchEvent: return ToConfUiMessage(confui_packet); // default ConfUiMessage with session & type only case ConfUiCmd::kAbort: return ToConfUiMessage(confui_packet); case ConfUiCmd::kStop: return ToConfUiMessage(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 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 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 confui_msg{session_id}; return confui_msg.SendOver(fd); } bool SendStopCmd(SharedFD fd, const std::string& session_id) { ConfUiGenericMessage 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& signed_response, const std::vector& 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& extra_data, const std::string& locale, const std::vector& 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 ToConfUiMessage( 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(message.session_id_, is_success, status_message); } template <> std::unique_ptr ToConfUiMessage( 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 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( 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 ToConfUiMessage( 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(message.session_id_, response); } template <> std::unique_ptr ToConfUiMessage( 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(message.session_id_, std::stoi(x), std::stoi(y)); } template <> std::unique_ptr ToConfUiMessage( 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(message.session_id_, response, sign, msg); } } // end of unnamed namespace } // end of namespace confui } // end of namespace cuttlefish