1 //
2 // Copyright (C) 2021 The Android Open Source Project
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15
16 #include "common/libs/confui/protocol.h"
17
18 #include <sstream>
19 #include <vector>
20
21 #include <android-base/strings.h>
22
23 #include "common/libs/confui/packet.h"
24 #include "common/libs/confui/utils.h"
25 #include "common/libs/fs/shared_buf.h"
26
27 namespace cuttlefish {
28 namespace confui {
29 namespace {
30 // default implementation of ToConfUiMessage
31 template <ConfUiCmd C>
ToConfUiMessage(const packet::ParsedPacket & message)32 std::unique_ptr<ConfUiMessage> ToConfUiMessage(
33 const packet::ParsedPacket& message) {
34 return std::make_unique<ConfUiGenericMessage<C>>(message.session_id_);
35 }
36
37 // these are specialized, and defined below
38 template <>
39 std::unique_ptr<ConfUiMessage> ToConfUiMessage<ConfUiCmd::kCliAck>(
40 const packet::ParsedPacket& message);
41 template <>
42 std::unique_ptr<ConfUiMessage> ToConfUiMessage<ConfUiCmd::kStart>(
43 const packet::ParsedPacket& message);
44 template <>
45 std::unique_ptr<ConfUiMessage> ToConfUiMessage<ConfUiCmd::kUserInputEvent>(
46 const packet::ParsedPacket& message);
47 template <>
48 std::unique_ptr<ConfUiMessage> ToConfUiMessage<ConfUiCmd::kUserTouchEvent>(
49 const packet::ParsedPacket& message);
50 template <>
51 std::unique_ptr<ConfUiMessage> ToConfUiMessage<ConfUiCmd::kCliRespond>(
52 const packet::ParsedPacket& message);
53
ToConfUiMessage(const packet::ParsedPacket & confui_packet)54 std::unique_ptr<ConfUiMessage> ToConfUiMessage(
55 const packet::ParsedPacket& confui_packet) {
56 const auto confui_cmd = ToCmd(confui_packet.type_);
57 switch (confui_cmd) {
58 // customized ConfUiMessage
59 case ConfUiCmd::kStart:
60 return ToConfUiMessage<ConfUiCmd::kStart>(confui_packet);
61 case ConfUiCmd::kCliAck:
62 return ToConfUiMessage<ConfUiCmd::kCliAck>(confui_packet);
63 case ConfUiCmd::kCliRespond:
64 return ToConfUiMessage<ConfUiCmd::kCliRespond>(confui_packet);
65 case ConfUiCmd::kUserInputEvent:
66 return ToConfUiMessage<ConfUiCmd::kUserInputEvent>(confui_packet);
67 case ConfUiCmd::kUserTouchEvent:
68 return ToConfUiMessage<ConfUiCmd::kUserTouchEvent>(confui_packet);
69 // default ConfUiMessage with session & type only
70 case ConfUiCmd::kAbort:
71 return ToConfUiMessage<ConfUiCmd::kAbort>(confui_packet);
72 case ConfUiCmd::kStop:
73 return ToConfUiMessage<ConfUiCmd::kStop>(confui_packet);
74 // these are errors
75 case ConfUiCmd::kUnknown:
76 default:
77 ConfUiLog(ERROR) << "ConfUiCmd value is not good for ToConfUiMessage: "
78 << ToString(confui_cmd);
79 break;
80 }
81 return {nullptr};
82 }
83 } // end of unnamed namespace
84
ToString(const ConfUiMessage & msg)85 std::string ToString(const ConfUiMessage& msg) { return msg.ToString(); }
86
RecvConfUiMsg(SharedFD fd)87 std::unique_ptr<ConfUiMessage> RecvConfUiMsg(SharedFD fd) {
88 if (!fd->IsOpen()) {
89 ConfUiLog(ERROR) << "file, socket, etc, is not open to read";
90 return {nullptr};
91 }
92 auto confui_packet_opt = packet::ReadPayload(fd);
93 if (!confui_packet_opt) {
94 ConfUiLog(ERROR) << "ReadPayload returns but with std::nullptr";
95 return {nullptr};
96 }
97
98 auto confui_packet = confui_packet_opt.value();
99 return ToConfUiMessage(confui_packet);
100 }
101
RecvConfUiMsg(const std::string & session_id,SharedFD fd)102 std::unique_ptr<ConfUiMessage> RecvConfUiMsg(const std::string& session_id,
103 SharedFD fd) {
104 auto conf_ui_msg = RecvConfUiMsg(fd);
105 if (!conf_ui_msg) {
106 return {nullptr};
107 }
108 auto recv_session_id = conf_ui_msg->GetSessionId();
109 if (session_id != recv_session_id) {
110 ConfUiLog(ERROR) << "Received Session ID (" << recv_session_id
111 << ") is not the expected one (" << session_id << ")";
112 return {nullptr};
113 }
114 return conf_ui_msg;
115 }
116
SendAbortCmd(SharedFD fd,const std::string & session_id)117 bool SendAbortCmd(SharedFD fd, const std::string& session_id) {
118 ConfUiGenericMessage<ConfUiCmd::kAbort> confui_msg{session_id};
119 return confui_msg.SendOver(fd);
120 }
121
SendStopCmd(SharedFD fd,const std::string & session_id)122 bool SendStopCmd(SharedFD fd, const std::string& session_id) {
123 ConfUiGenericMessage<ConfUiCmd::kStop> confui_msg{session_id};
124 return confui_msg.SendOver(fd);
125 }
126
SendAck(SharedFD fd,const std::string & session_id,const bool is_success,const std::string & status_message)127 bool SendAck(SharedFD fd, const std::string& session_id, const bool is_success,
128 const std::string& status_message) {
129 ConfUiAckMessage confui_msg{session_id, is_success, status_message};
130 return confui_msg.SendOver(fd);
131 }
132
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)133 bool SendResponse(SharedFD fd, const std::string& session_id,
134 const UserResponse::type& plain_selection,
135 const std::vector<std::uint8_t>& signed_response,
136 const std::vector<std::uint8_t>& message) {
137 ConfUiCliResponseMessage confui_msg{session_id, plain_selection,
138 signed_response, message};
139 return confui_msg.SendOver(fd);
140 }
141
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)142 bool SendStartCmd(SharedFD fd, const std::string& session_id,
143 const std::string& prompt_text,
144 const std::vector<std::uint8_t>& extra_data,
145 const std::string& locale,
146 const std::vector<teeui::UIOption>& ui_opts) {
147 ConfUiStartMessage confui_msg{session_id, prompt_text, extra_data, locale,
148 ui_opts};
149 return confui_msg.SendOver(fd);
150 }
151
152 // this is only for deliverSecureInputEvent
SendUserSelection(SharedFD fd,const std::string & session_id,const UserResponse::type & confirm_cancel)153 bool SendUserSelection(SharedFD fd, const std::string& session_id,
154 const UserResponse::type& confirm_cancel) {
155 ConfUiUserSelectionMessage confui_msg{session_id, confirm_cancel};
156 return confui_msg.SendOver(fd);
157 }
158
159 // specialized ToConfUiMessage()
160 namespace {
161 template <>
ToConfUiMessage(const packet::ParsedPacket & message)162 std::unique_ptr<ConfUiMessage> ToConfUiMessage<ConfUiCmd::kCliAck>(
163 const packet::ParsedPacket& message) {
164 auto type = ToCmd(message.type_);
165 auto& contents = message.additional_info_;
166 if (type != ConfUiCmd::kCliAck) {
167 ConfUiLog(ERROR) << "Received cmd is not ack but " << ToString(type);
168 return {nullptr};
169 }
170
171 if (contents.size() != 2) {
172 ConfUiLog(ERROR)
173 << "Ack message should only have pass/fail and a status message";
174 return {nullptr};
175 }
176
177 const std::string success_str(contents[0].begin(), contents[0].end());
178 const bool is_success = (success_str == "success");
179 const std::string status_message(contents[1].begin(), contents[1].end());
180 return std::make_unique<ConfUiAckMessage>(message.session_id_, is_success,
181 status_message);
182 }
183
184 template <>
ToConfUiMessage(const packet::ParsedPacket & message)185 std::unique_ptr<ConfUiMessage> ToConfUiMessage<ConfUiCmd::kStart>(
186 const packet::ParsedPacket& message) {
187 /*
188 * additional_info_[0]: prompt text
189 * additional_info_[1]: extra data
190 * additional_info_[2]: locale
191 * additional_info_[3]: UIOptions
192 *
193 */
194 if (message.additional_info_.size() < 3) {
195 ConfUiLog(ERROR) << "ConfUiMessage for kStart is ill-formatted: "
196 << packet::ToString(message);
197 return {nullptr};
198 }
199 std::vector<teeui::UIOption> ui_opts;
200 bool has_ui_option = (message.additional_info_.size() == 4) &&
201 !(message.additional_info_[3].empty());
202 if (has_ui_option) {
203 std::string ui_opts_string{message.additional_info_[3].begin(),
204 message.additional_info_[3].end()};
205 auto tokens = android::base::Split(ui_opts_string, ",");
206 for (auto token : tokens) {
207 auto ui_opt_optional = ToUiOption(token);
208 if (!ui_opt_optional) {
209 ConfUiLog(ERROR) << "Wrong UiOption String : " << token;
210 return {nullptr};
211 }
212 ui_opts.emplace_back(ui_opt_optional.value());
213 }
214 }
215 auto sm = std::make_unique<ConfUiStartMessage>(
216 message.session_id_,
217 std::string(message.additional_info_[0].begin(),
218 message.additional_info_[0].end()),
219 message.additional_info_[1],
220 std::string(message.additional_info_[2].begin(),
221 message.additional_info_[2].end()),
222 ui_opts);
223 return sm;
224 }
225
226 template <>
ToConfUiMessage(const packet::ParsedPacket & message)227 std::unique_ptr<ConfUiMessage> ToConfUiMessage<ConfUiCmd::kUserInputEvent>(
228 const packet::ParsedPacket& message) {
229 if (message.additional_info_.size() < 1) {
230 ConfUiLog(ERROR)
231 << "kUserInputEvent message should have at least one additional_info_";
232 return {nullptr};
233 }
234 auto response = std::string{message.additional_info_[0].begin(),
235 message.additional_info_[0].end()};
236 return std::make_unique<ConfUiUserSelectionMessage>(message.session_id_,
237 response);
238 }
239
240 template <>
ToConfUiMessage(const packet::ParsedPacket & message)241 std::unique_ptr<ConfUiMessage> ToConfUiMessage<ConfUiCmd::kUserTouchEvent>(
242 const packet::ParsedPacket& message) {
243 if (message.additional_info_.size() < 2) {
244 ConfUiLog(ERROR)
245 << "kUserTouchEvent message should have at least two additional_info_";
246 return {nullptr};
247 }
248 auto x = std::string(message.additional_info_[0].begin(),
249 message.additional_info_[0].end());
250 auto y = std::string(message.additional_info_[1].begin(),
251 message.additional_info_[1].end());
252 return std::make_unique<ConfUiUserTouchMessage>(message.session_id_,
253 std::stoi(x), std::stoi(y));
254 }
255
256 template <>
ToConfUiMessage(const packet::ParsedPacket & message)257 std::unique_ptr<ConfUiMessage> ToConfUiMessage<ConfUiCmd::kCliRespond>(
258 const packet::ParsedPacket& message) {
259 if (message.additional_info_.size() < 3) {
260 ConfUiLog(ERROR)
261 << "kCliRespond message should have at least two additional info";
262 return {nullptr};
263 }
264 auto response = std::string{message.additional_info_[0].begin(),
265 message.additional_info_[0].end()};
266 auto sign = message.additional_info_[1];
267 auto msg = message.additional_info_[2];
268 return std::make_unique<ConfUiCliResponseMessage>(message.session_id_,
269 response, sign, msg);
270 }
271 } // end of unnamed namespace
272 } // end of namespace confui
273 } // end of namespace cuttlefish
274