• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *
3  * Copyright 2019, The Android Open Source Project
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 #include "TrustyConfirmationUI.h"
19 
20 #include <cutils/properties.h>
21 
22 namespace android {
23 namespace hardware {
24 namespace confirmationui {
25 namespace V1_0 {
26 namespace implementation {
27 
28 using ::teeui::MsgString;
29 using ::teeui::MsgVector;
30 using ::android::hardware::keymaster::V4_0::HardwareAuthToken;
31 using TeeuiRc = ::teeui::ResponseCode;
32 
33 namespace {
convertUIOption(UIOption uio)34 teeui::UIOption convertUIOption(UIOption uio) {
35     static_assert(uint32_t(UIOption::AccessibilityInverted) ==
36                           uint32_t(teeui::UIOption::AccessibilityInverted) &&
37                       uint32_t(UIOption::AccessibilityMagnified) ==
38                           uint32_t(teeui::UIOption::AccessibilityMagnified),
39                   "teeui::UIOPtion and ::android::hardware::confirmationui::V1_0::UIOption "
40                   "are out of sync");
41     return teeui::UIOption(uio);
42 }
43 
hidl2MsgString(const hidl_string & s)44 inline MsgString hidl2MsgString(const hidl_string& s) {
45     return {s.c_str(), s.c_str() + s.size()};
46 }
hidl2MsgVector(const hidl_vec<T> & v)47 template <typename T> inline MsgVector<T> hidl2MsgVector(const hidl_vec<T>& v) {
48     return {v};
49 }
50 
hidl2MsgVector(const hidl_vec<UIOption> & v)51 inline MsgVector<teeui::UIOption> hidl2MsgVector(const hidl_vec<UIOption>& v) {
52     MsgVector<teeui::UIOption> result(v.size());
53     for (unsigned int i = 0; i < v.size(); ++i) {
54         result[i] = convertUIOption(v[i]);
55     }
56     return result;
57 }
58 }  // namespace
59 
ConnectToHost()60 cuttlefish::SharedFD TrustyConfirmationUI::ConnectToHost() {
61     using namespace std::chrono_literals;
62     while (true) {
63         auto host_fd = cuttlefish::SharedFD::VsockClient(2, host_vsock_port_, SOCK_STREAM);
64         if (host_fd->IsOpen()) {
65             ConfUiLog(INFO) << "Client connection is established";
66             return host_fd;
67         }
68         ConfUiLog(INFO) << "host service is not on. Sleep for 500 ms";
69         std::this_thread::sleep_for(500ms);
70     }
71 }
72 
TrustyConfirmationUI()73 TrustyConfirmationUI::TrustyConfirmationUI()
74     : listener_state_(ListenerState::None),
75       prompt_result_(ResponseCode::Ignored), host_vsock_port_{static_cast<int>(property_get_int64(
76                                                  "ro.boot.vsock_confirmationui_port", 7700))},
77       current_session_id_{10} {
78     ConfUiLog(INFO) << "Connecting to Confirmation UI host listening on port " << host_vsock_port_;
79     host_fd_ = ConnectToHost();
__anone5301d570202() 80     auto fetching_cmd = [this]() { HostMessageFetcherLoop(); };
81     if (host_fd_->IsOpen()) {
82         host_cmd_fetcher_thread_ = std::thread(fetching_cmd);
83     }
84 }
85 
~TrustyConfirmationUI()86 TrustyConfirmationUI::~TrustyConfirmationUI() {
87     if (host_fd_->IsOpen()) {
88         host_fd_->Close();
89     }
90     if (host_cmd_fetcher_thread_.joinable()) {
91         host_cmd_fetcher_thread_.join();
92     }
93 
94     if (listener_state_ != ListenerState::None) {
95         callback_thread_.join();
96     }
97 }
98 
HostMessageFetcherLoop()99 void TrustyConfirmationUI::HostMessageFetcherLoop() {
100     while (true) {
101         if (!host_fd_->IsOpen()) {
102             // this happens when TrustyConfirmationUI is destroyed
103             ConfUiLog(ERROR) << "host_fd_ is not open";
104             return;
105         }
106         auto msg = cuttlefish::confui::RecvConfUiMsg(host_fd_);
107         if (!msg) {
108             // socket is broken for now
109             return;
110         }
111         {
112             std::unique_lock<std::mutex> lk(current_session_lock_);
113             if (!current_session_ || msg->GetSessionId() != current_session_->GetSessionId()) {
114                 if (!current_session_) {
115                     ConfUiLog(ERROR) << "msg is received but session is null";
116                     continue;
117                 }
118                 ConfUiLog(ERROR) << "session id mismatch, so ignored"
119                                  << "Received for " << msg->GetSessionId()
120                                  << " but currently running " << current_session_->GetSessionId();
121                 continue;
122             }
123             current_session_->Push(std::move(msg));
124         }
125         listener_state_condv_.notify_all();
126     }
127 }
128 
RunSession(sp<IConfirmationResultCallback> resultCB,hidl_string promptText,hidl_vec<uint8_t> extraData,hidl_string locale,hidl_vec<UIOption> uiOptions)129 void TrustyConfirmationUI::RunSession(sp<IConfirmationResultCallback> resultCB,
130                                       hidl_string promptText, hidl_vec<uint8_t> extraData,
131                                       hidl_string locale, hidl_vec<UIOption> uiOptions) {
132     cuttlefish::SharedFD fd = host_fd_;
133     // ownership of the fd is passed to GuestSession
134     {
135         std::unique_lock<std::mutex> lk(current_session_lock_);
136         current_session_ = std::make_unique<GuestSession>(
137             current_session_id_, listener_state_, listener_state_lock_, listener_state_condv_, fd,
138             hidl2MsgString(promptText), hidl2MsgVector(extraData), hidl2MsgString(locale),
139             hidl2MsgVector(uiOptions));
140     }
141 
142     auto [rc, msg, token] = current_session_->PromptUserConfirmation();
143 
144     std::unique_lock<std::mutex> lock(listener_state_lock_);  // for listener_state_
145     bool do_callback = (listener_state_ == ListenerState::Interactive ||
146                         listener_state_ == ListenerState::SetupDone) &&
147                        resultCB;
148     prompt_result_ = rc;
149     listener_state_ = ListenerState::Terminating;
150     lock.unlock();
151     if (do_callback) {
152         auto error = resultCB->result(prompt_result_, msg, token);
153         if (!error.isOk()) {
154             ConfUiLog(ERROR) << "Result callback failed " << error.description();
155         }
156         ConfUiLog(INFO) << "Result callback returned.";
157     } else {
158         listener_state_condv_.notify_all();
159     }
160 }
161 
162 // Methods from ::android::hardware::confirmationui::V1_0::IConfirmationUI
163 // follow.
promptUserConfirmation(const sp<IConfirmationResultCallback> & resultCB,const hidl_string & promptText,const hidl_vec<uint8_t> & extraData,const hidl_string & locale,const hidl_vec<UIOption> & uiOptions)164 Return<ResponseCode> TrustyConfirmationUI::promptUserConfirmation(
165     const sp<IConfirmationResultCallback>& resultCB, const hidl_string& promptText,
166     const hidl_vec<uint8_t>& extraData, const hidl_string& locale,
167     const hidl_vec<UIOption>& uiOptions) {
168     std::unique_lock<std::mutex> stateLock(listener_state_lock_, std::defer_lock);
169     ConfUiLog(INFO) << "promptUserConfirmation is called";
170 
171     if (!stateLock.try_lock()) {
172         return ResponseCode::OperationPending;
173     }
174     switch (listener_state_) {
175     case ListenerState::None:
176         break;
177     case ListenerState::Starting:
178     case ListenerState::SetupDone:
179     case ListenerState::Interactive:
180         return ResponseCode::OperationPending;
181     case ListenerState::Terminating:
182         callback_thread_.join();
183         listener_state_ = ListenerState::None;
184         break;
185     default:
186         return ResponseCode::Unexpected;
187     }
188     assert(listener_state_ == ListenerState::None);
189     listener_state_ = ListenerState::Starting;
190     ConfUiLog(INFO) << "Per promptUserConfirmation, "
191                     << "an active TEE UI session starts";
192     current_session_id_++;
193     auto worker = [this](const sp<IConfirmationResultCallback>& resultCB,
194                          const hidl_string& promptText, const hidl_vec<uint8_t>& extraData,
195                          const hidl_string& locale, const hidl_vec<UIOption>& uiOptions) {
196         RunSession(resultCB, promptText, extraData, locale, uiOptions);
197     };
198     callback_thread_ = std::thread(worker, resultCB, promptText, extraData, locale, uiOptions);
199 
200     listener_state_condv_.wait(stateLock, [this] {
201         return listener_state_ == ListenerState::SetupDone ||
202                listener_state_ == ListenerState::Interactive ||
203                listener_state_ == ListenerState::Terminating;
204     });
205     if (listener_state_ == ListenerState::Terminating) {
206         callback_thread_.join();
207         listener_state_ = ListenerState::None;
208         if (prompt_result_ == ResponseCode::Canceled) {
209             // VTS expects this
210             return ResponseCode::OK;
211         }
212         return prompt_result_;
213     }
214     return ResponseCode::OK;
215 }
216 
217 Return<ResponseCode>
deliverSecureInputEvent(const HardwareAuthToken & auth_token)218 TrustyConfirmationUI::deliverSecureInputEvent(const HardwareAuthToken& auth_token) {
219     ConfUiLog(INFO) << "deliverSecureInputEvent is called";
220     ResponseCode rc = ResponseCode::Ignored;
221     {
222         std::unique_lock<std::mutex> lock(current_session_lock_);
223         if (!current_session_) {
224             return rc;
225         }
226         return current_session_->DeliverSecureInputEvent(auth_token);
227     }
228 }
229 
abort()230 Return<void> TrustyConfirmationUI::abort() {
231     {
232         std::unique_lock<std::mutex> lock(current_session_lock_);
233         if (!current_session_) {
234             return Void();
235         }
236         return current_session_->Abort();
237     }
238 }
239 
createTrustyConfirmationUI()240 android::sp<IConfirmationUI> createTrustyConfirmationUI() {
241     return new TrustyConfirmationUI();
242 }
243 
244 }  // namespace implementation
245 }  // namespace V1_0
246 }  // namespace confirmationui
247 }  // namespace hardware
248 }  // namespace android
249