• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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 
17 #include "apc_compat.hpp"
18 #include <android-base/logging.h>
19 #include <android/hardware/confirmationui/1.0/IConfirmationUI.h>
20 #include <hwbinder/IBinder.h>
21 
22 #include <aidl/android/hardware/confirmationui/BnConfirmationResultCallback.h>
23 #include <aidl/android/hardware/confirmationui/IConfirmationResultCallback.h>
24 #include <aidl/android/hardware/confirmationui/IConfirmationUI.h>
25 #include <aidl/android/hardware/confirmationui/UIOption.h>
26 #include <android/binder_manager.h>
27 
28 #include <memory>
29 #include <string>
30 #include <thread>
31 #include <vector>
32 
33 #define LOG_TAG "keystore2_apc_compat"
34 
35 namespace keystore2 {
36 
37 using android::sp;
38 using android::hardware::hidl_death_recipient;
39 using android::hardware::hidl_vec;
40 using android::hardware::Return;
41 using android::hardware::Status;
42 using HidlConfirmationResultCb =
43     android::hardware::confirmationui::V1_0::IConfirmationResultCallback;
44 using HidlConfirmationUI = android::hardware::confirmationui::V1_0::IConfirmationUI;
45 using android::hardware::confirmationui::V1_0::ResponseCode;
46 using HidlUIOptions = android::hardware::confirmationui::V1_0::UIOption;
47 
48 using AidlConfirmationUI = ::aidl::android::hardware::confirmationui::IConfirmationUI;
49 using AidlBnConfirmationResultCb =
50     ::aidl::android::hardware::confirmationui::BnConfirmationResultCallback;
51 using AidlUIOptions = ::aidl::android::hardware::confirmationui::UIOption;
52 
53 class CompatSessionCB {
54   public:
55     void
finalize(uint32_t responseCode,ApcCompatCallback callback,std::optional<std::reference_wrapper<const std::vector<uint8_t>>> dataConfirmed,std::optional<std::reference_wrapper<const std::vector<uint8_t>>> confirmationToken)56     finalize(uint32_t responseCode, ApcCompatCallback callback,
57              std::optional<std::reference_wrapper<const std::vector<uint8_t>>> dataConfirmed,
58              std::optional<std::reference_wrapper<const std::vector<uint8_t>>> confirmationToken) {
59         if (callback.result != nullptr) {
60             size_t dataConfirmedSize = 0;
61             const uint8_t* dataConfirmedPtr = nullptr;
62             size_t confirmationTokenSize = 0;
63             const uint8_t* confirmationTokenPtr = nullptr;
64             if (responseCode == APC_COMPAT_ERROR_OK) {
65                 if (dataConfirmed) {
66                     dataConfirmedPtr = dataConfirmed->get().data();
67                     dataConfirmedSize = dataConfirmed->get().size();
68                 }
69                 if (confirmationToken) {
70                     confirmationTokenPtr = confirmationToken->get().data();
71                     confirmationTokenSize = confirmationToken->get().size();
72                 }
73             }
74             callback.result(callback.data, responseCode, dataConfirmedPtr, dataConfirmedSize,
75                             confirmationTokenPtr, confirmationTokenSize);
76         }
77     }
78 };
79 
80 class ConfuiHidlCompatSession : public HidlConfirmationResultCb,
81                                 public hidl_death_recipient,
82                                 public CompatSessionCB {
83   public:
tryGetService()84     static sp<ConfuiHidlCompatSession> tryGetService() {
85         sp<HidlConfirmationUI> service = HidlConfirmationUI::tryGetService();
86         if (service) {
87             return sp<ConfuiHidlCompatSession>(new ConfuiHidlCompatSession(std::move(service)));
88         } else {
89             return nullptr;
90         }
91     }
92 
promptUserConfirmation(ApcCompatCallback callback,const char * prompt_text,const uint8_t * extra_data,size_t extra_data_size,const char * locale,ApcCompatUiOptions ui_options)93     uint32_t promptUserConfirmation(ApcCompatCallback callback, const char* prompt_text,
94                                     const uint8_t* extra_data, size_t extra_data_size,
95                                     const char* locale, ApcCompatUiOptions ui_options) {
96         std::string hidl_prompt(prompt_text);
97         std::vector<uint8_t> hidl_extra(extra_data, extra_data + extra_data_size);
98         std::vector<HidlUIOptions> hidl_ui_options;
99         if (ui_options.inverted) {
100             hidl_ui_options.push_back(HidlUIOptions::AccessibilityInverted);
101         }
102         if (ui_options.magnified) {
103             hidl_ui_options.push_back(HidlUIOptions::AccessibilityMagnified);
104         }
105         auto lock = std::lock_guard(callback_lock_);
106         if (callback_.result != nullptr) {
107             return APC_COMPAT_ERROR_OPERATION_PENDING;
108         }
109         auto err = service_->linkToDeath(sp(this), 0);
110         if (!err.isOk()) {
111             LOG(ERROR) << "Communication error: promptUserConfirmation: "
112                           "Trying to register death recipient: "
113                        << err.description();
114             return APC_COMPAT_ERROR_SYSTEM_ERROR;
115         }
116 
117         auto rc = service_->promptUserConfirmation(sp(this), hidl_prompt, hidl_extra, locale,
118                                                    hidl_ui_options);
119         if (!rc.isOk()) {
120             LOG(ERROR) << "Communication error: promptUserConfirmation: " << rc.description();
121         }
122         if (rc == ResponseCode::OK) {
123             callback_ = callback;
124         }
125         return responseCode2Compat(rc.withDefault(ResponseCode::SystemError));
126     }
127 
abort()128     void abort() { service_->abort(); }
129 
finalize(ResponseCode responseCode,const hidl_vec<uint8_t> & dataConfirmed,const hidl_vec<uint8_t> & confirmationToken)130     void finalize(ResponseCode responseCode, const hidl_vec<uint8_t>& dataConfirmed,
131                   const hidl_vec<uint8_t>& confirmationToken) {
132         ApcCompatCallback callback;
133         {
134             auto lock = std::lock_guard(callback_lock_);
135             // Calling the callback consumes the callback data structure. We have to make
136             // sure that it can only be called once.
137             callback = callback_;
138             callback_ = {nullptr, nullptr};
139             // Unlock the callback_lock_ here. It must never be held while calling the callback.
140         }
141 
142         if (callback.result != nullptr) {
143             service_->unlinkToDeath(sp(this));
144 
145             std::vector<uint8_t> data = dataConfirmed;
146             std::vector<uint8_t> token = confirmationToken;
147 
148             CompatSessionCB::finalize(responseCode2Compat(responseCode), callback, data, token);
149         }
150     }
151 
152     // HidlConfirmationResultCb overrides:
result(ResponseCode responseCode,const hidl_vec<uint8_t> & dataConfirmed,const hidl_vec<uint8_t> & confirmationToken)153     android::hardware::Return<void> result(ResponseCode responseCode,
154                                            const hidl_vec<uint8_t>& dataConfirmed,
155                                            const hidl_vec<uint8_t>& confirmationToken) override {
156         finalize(responseCode, dataConfirmed, confirmationToken);
157         return Status::ok();
158     };
159 
serviceDied(uint64_t,const::android::wp<::android::hidl::base::V1_0::IBase> &)160     void serviceDied(uint64_t /* cookie */,
161                      const ::android::wp<::android::hidl::base::V1_0::IBase>& /* who */) override {
162         finalize(ResponseCode::SystemError, {}, {});
163     }
164 
responseCode2Compat(ResponseCode rc)165     static uint32_t responseCode2Compat(ResponseCode rc) {
166         switch (rc) {
167         case ResponseCode::OK:
168             return APC_COMPAT_ERROR_OK;
169         case ResponseCode::Canceled:
170             return APC_COMPAT_ERROR_CANCELLED;
171         case ResponseCode::Aborted:
172             return APC_COMPAT_ERROR_ABORTED;
173         case ResponseCode::OperationPending:
174             return APC_COMPAT_ERROR_OPERATION_PENDING;
175         case ResponseCode::Ignored:
176             return APC_COMPAT_ERROR_IGNORED;
177         case ResponseCode::SystemError:
178         case ResponseCode::Unimplemented:
179         case ResponseCode::Unexpected:
180         case ResponseCode::UIError:
181         case ResponseCode::UIErrorMissingGlyph:
182         case ResponseCode::UIErrorMessageTooLong:
183         case ResponseCode::UIErrorMalformedUTF8Encoding:
184         default:
185             return APC_COMPAT_ERROR_SYSTEM_ERROR;
186         }
187     }
188 
189   private:
ConfuiHidlCompatSession(sp<HidlConfirmationUI> service)190     ConfuiHidlCompatSession(sp<HidlConfirmationUI> service)
191         : service_(service), callback_{nullptr, nullptr} {}
192     sp<HidlConfirmationUI> service_;
193 
194     // The callback_lock_ protects the callback_ field against concurrent modification.
195     // IMPORTANT: It must never be held while calling the call back.
196     std::mutex callback_lock_;
197     ApcCompatCallback callback_;
198 };
199 
200 class ConfuiAidlCompatSession : public AidlBnConfirmationResultCb, public CompatSessionCB {
201   public:
tryGetService()202     static std::shared_ptr<ConfuiAidlCompatSession> tryGetService() {
203         constexpr const char confirmationUIServiceName[] =
204             "android.hardware.confirmationui.IConfirmationUI/default";
205         if (!AServiceManager_isDeclared(confirmationUIServiceName)) {
206             LOG(INFO) << confirmationUIServiceName << " is not declared in VINTF";
207             return nullptr;
208         }
209         std::shared_ptr<AidlConfirmationUI> aidlService = AidlConfirmationUI::fromBinder(
210             ndk::SpAIBinder(AServiceManager_waitForService(confirmationUIServiceName)));
211         if (aidlService) {
212             return ::ndk::SharedRefBase::make<ConfuiAidlCompatSession>(aidlService);
213         }
214 
215         return nullptr;
216     }
217 
promptUserConfirmation(ApcCompatCallback callback,const char * prompt_text,const uint8_t * extra_data,size_t extra_data_size,const char * locale,ApcCompatUiOptions ui_options)218     uint32_t promptUserConfirmation(ApcCompatCallback callback, const char* prompt_text,
219                                     const uint8_t* extra_data, size_t extra_data_size,
220                                     const char* locale, ApcCompatUiOptions ui_options) {
221         std::vector<uint8_t> aidl_prompt(prompt_text, prompt_text + strlen(prompt_text));
222         std::vector<uint8_t> aidl_extra(extra_data, extra_data + extra_data_size);
223         std::vector<AidlUIOptions> aidl_ui_options;
224         if (ui_options.inverted) {
225             aidl_ui_options.push_back(AidlUIOptions::ACCESSIBILITY_INVERTED);
226         }
227         if (ui_options.magnified) {
228             aidl_ui_options.push_back(AidlUIOptions::ACCESSIBILITY_MAGNIFIED);
229         }
230         auto lock = std::lock_guard(callback_lock_);
231         if (callback_.result != nullptr) {
232             return APC_COMPAT_ERROR_OPERATION_PENDING;
233         }
234 
235         if (!aidlService_) {
236             return APC_COMPAT_ERROR_SYSTEM_ERROR;
237         }
238         auto linkRet =
239             AIBinder_linkToDeath(aidlService_->asBinder().get(), death_recipient_.get(), this);
240         if (linkRet != STATUS_OK) {
241             LOG(ERROR) << "Communication error: promptUserConfirmation: "
242                           "Trying to register death recipient: ";
243             return APC_COMPAT_ERROR_SYSTEM_ERROR;
244         }
245 
246         auto rc = aidlService_->promptUserConfirmation(ref<ConfuiAidlCompatSession>(), aidl_prompt,
247                                                        aidl_extra, locale, aidl_ui_options);
248         int ret = getReturnCode(rc);
249         if (ret == AidlConfirmationUI::OK) {
250             callback_ = callback;
251         } else {
252             LOG(ERROR) << "Communication error: promptUserConfirmation: " << rc.getDescription();
253         }
254         return responseCode2Compat(ret);
255     }
256 
abort()257     void abort() {
258         if (aidlService_) {
259             aidlService_->abort();
260         }
261     }
262 
263     void
finalize(int32_t responseCode,std::optional<std::reference_wrapper<const std::vector<uint8_t>>> dataConfirmed,std::optional<std::reference_wrapper<const std::vector<uint8_t>>> confirmationToken)264     finalize(int32_t responseCode,
265              std::optional<std::reference_wrapper<const std::vector<uint8_t>>> dataConfirmed,
266              std::optional<std::reference_wrapper<const std::vector<uint8_t>>> confirmationToken) {
267         ApcCompatCallback callback;
268         {
269             auto lock = std::lock_guard(callback_lock_);
270             // Calling the callback consumes the callback data structure. We have to make
271             // sure that it can only be called once.
272             callback = callback_;
273             callback_ = {nullptr, nullptr};
274             // Unlock the callback_lock_ here. It must never be held while calling the callback.
275         }
276 
277         if (callback.result != nullptr) {
278             if (aidlService_) {
279                 AIBinder_unlinkToDeath(aidlService_->asBinder().get(), death_recipient_.get(),
280                                        this);
281             }
282             CompatSessionCB::finalize(responseCode2Compat(responseCode), callback, dataConfirmed,
283                                       confirmationToken);
284         }
285     }
286 
287     // AidlBnConfirmationResultCb overrides:
result(int32_t responseCode,const std::vector<uint8_t> & dataConfirmed,const std::vector<uint8_t> & confirmationToken)288     ::ndk::ScopedAStatus result(int32_t responseCode, const std::vector<uint8_t>& dataConfirmed,
289                                 const std::vector<uint8_t>& confirmationToken) override {
290         finalize(responseCode, dataConfirmed, confirmationToken);
291         return ::ndk::ScopedAStatus::ok();
292     };
293 
serviceDied()294     void serviceDied() {
295         aidlService_.reset();
296         aidlService_ = nullptr;
297         finalize(AidlConfirmationUI::SYSTEM_ERROR, {}, {});
298     }
299 
binderDiedCallbackAidl(void * ptr)300     static void binderDiedCallbackAidl(void* ptr) {
301         LOG(ERROR) << __func__ << " : ConfuiAidlCompatSession Service died.";
302         auto aidlSession = static_cast<ConfuiAidlCompatSession*>(ptr);
303         if (aidlSession == nullptr) {
304             LOG(ERROR) << __func__ << ": Null ConfuiAidlCompatSession HAL died.";
305             return;
306         }
307         aidlSession->serviceDied();
308     }
309 
getReturnCode(const::ndk::ScopedAStatus & result)310     int getReturnCode(const ::ndk::ScopedAStatus& result) {
311         if (result.isOk()) return AidlConfirmationUI::OK;
312 
313         if (result.getExceptionCode() == EX_SERVICE_SPECIFIC) {
314             return static_cast<int>(result.getServiceSpecificError());
315         }
316         return result.getStatus();
317     }
318 
responseCode2Compat(int32_t rc)319     uint32_t responseCode2Compat(int32_t rc) {
320         switch (rc) {
321         case AidlConfirmationUI::OK:
322             return APC_COMPAT_ERROR_OK;
323         case AidlConfirmationUI::CANCELED:
324             return APC_COMPAT_ERROR_CANCELLED;
325         case AidlConfirmationUI::ABORTED:
326             return APC_COMPAT_ERROR_ABORTED;
327         case AidlConfirmationUI::OPERATION_PENDING:
328             return APC_COMPAT_ERROR_OPERATION_PENDING;
329         case AidlConfirmationUI::IGNORED:
330             return APC_COMPAT_ERROR_IGNORED;
331         case AidlConfirmationUI::SYSTEM_ERROR:
332         case AidlConfirmationUI::UNIMPLEMENTED:
333         case AidlConfirmationUI::UNEXPECTED:
334         case AidlConfirmationUI::UI_ERROR:
335         case AidlConfirmationUI::UI_ERROR_MISSING_GLYPH:
336         case AidlConfirmationUI::UI_ERROR_MESSAGE_TOO_LONG:
337         case AidlConfirmationUI::UI_ERROR_MALFORMED_UTF8ENCODING:
338         default:
339             return APC_COMPAT_ERROR_SYSTEM_ERROR;
340         }
341     }
342 
ConfuiAidlCompatSession(std::shared_ptr<AidlConfirmationUI> service)343     ConfuiAidlCompatSession(std::shared_ptr<AidlConfirmationUI> service)
344         : aidlService_(service), callback_{nullptr, nullptr} {
345         death_recipient_ = ::ndk::ScopedAIBinder_DeathRecipient(
346             AIBinder_DeathRecipient_new(binderDiedCallbackAidl));
347     }
348 
349     virtual ~ConfuiAidlCompatSession() = default;
350     ConfuiAidlCompatSession(const ConfuiAidlCompatSession&) = delete;
351     ConfuiAidlCompatSession& operator=(const ConfuiAidlCompatSession&) = delete;
352 
353   private:
354     std::shared_ptr<AidlConfirmationUI> aidlService_;
355 
356     // The callback_lock_ protects the callback_ field against concurrent modification.
357     // IMPORTANT: It must never be held while calling the call back.
358     std::mutex callback_lock_;
359     ApcCompatCallback callback_;
360 
361     ::ndk::ScopedAIBinder_DeathRecipient death_recipient_;
362 };
363 
364 class ApcCompatSession {
365   public:
getApcCompatSession()366     static ApcCompatServiceHandle getApcCompatSession() {
367         auto aidlCompatSession = ConfuiAidlCompatSession::tryGetService();
368         if (aidlCompatSession) {
369             return new ApcCompatSession(std::move(aidlCompatSession), nullptr);
370         }
371 
372         sp<ConfuiHidlCompatSession> hidlCompatSession = ConfuiHidlCompatSession::tryGetService();
373         if (hidlCompatSession) {
374             return new ApcCompatSession(nullptr, std::move(hidlCompatSession));
375         }
376 
377         LOG(ERROR) << "ConfirmationUI: Not found Service";
378         return nullptr;
379     }
380 
promptUserConfirmation(ApcCompatCallback callback,const char * prompt_text,const uint8_t * extra_data,size_t extra_data_size,char const * locale,ApcCompatUiOptions ui_options)381     uint32_t promptUserConfirmation(ApcCompatCallback callback, const char* prompt_text,
382                                     const uint8_t* extra_data, size_t extra_data_size,
383                                     char const* locale, ApcCompatUiOptions ui_options) {
384         if (aidlCompatSession_) {
385             return aidlCompatSession_->promptUserConfirmation(callback, prompt_text, extra_data,
386                                                               extra_data_size, locale, ui_options);
387         } else {
388             return hidlCompatSession_->promptUserConfirmation(callback, prompt_text, extra_data,
389                                                               extra_data_size, locale, ui_options);
390         }
391     }
392 
abortUserConfirmation()393     void abortUserConfirmation() {
394         if (aidlCompatSession_) {
395             return aidlCompatSession_->abort();
396         } else {
397             return hidlCompatSession_->abort();
398         }
399     }
400 
closeUserConfirmationService()401     void closeUserConfirmationService() {
402         // Closing the handle implicitly aborts an ongoing sessions.
403         // Note that a resulting callback is still safely conducted, because we only delete a
404         // StrongPointer below. libhwbinder still owns another StrongPointer to this session.
405         abortUserConfirmation();
406     }
407 
ApcCompatSession(std::shared_ptr<ConfuiAidlCompatSession> aidlCompatSession,sp<ConfuiHidlCompatSession> hidlCompatSession)408     ApcCompatSession(std::shared_ptr<ConfuiAidlCompatSession> aidlCompatSession,
409                      sp<ConfuiHidlCompatSession> hidlCompatSession)
410         : aidlCompatSession_(aidlCompatSession), hidlCompatSession_(hidlCompatSession) {}
411 
412   private:
413     std::shared_ptr<ConfuiAidlCompatSession> aidlCompatSession_;
414     sp<ConfuiHidlCompatSession> hidlCompatSession_;
415 };
416 }  // namespace keystore2
417 
418 using namespace keystore2;
419 
tryGetUserConfirmationService()420 ApcCompatServiceHandle tryGetUserConfirmationService() {
421     return reinterpret_cast<ApcCompatServiceHandle>(ApcCompatSession::getApcCompatSession());
422 }
423 
promptUserConfirmation(ApcCompatServiceHandle handle,ApcCompatCallback callback,const char * prompt_text,const uint8_t * extra_data,size_t extra_data_size,char const * locale,ApcCompatUiOptions ui_options)424 uint32_t promptUserConfirmation(ApcCompatServiceHandle handle, ApcCompatCallback callback,
425                                 const char* prompt_text, const uint8_t* extra_data,
426                                 size_t extra_data_size, char const* locale,
427                                 ApcCompatUiOptions ui_options) {
428     auto session = reinterpret_cast<ApcCompatSession*>(handle);
429     return session->promptUserConfirmation(callback, prompt_text, extra_data, extra_data_size,
430                                            locale, ui_options);
431 }
432 
abortUserConfirmation(ApcCompatServiceHandle handle)433 void abortUserConfirmation(ApcCompatServiceHandle handle) {
434     auto session = reinterpret_cast<ApcCompatSession*>(handle);
435     session->abortUserConfirmation();
436 }
437 
closeUserConfirmationService(ApcCompatServiceHandle handle)438 void closeUserConfirmationService(ApcCompatServiceHandle handle) {
439     auto session = reinterpret_cast<ApcCompatSession*>(handle);
440     session->closeUserConfirmationService();
441     delete reinterpret_cast<ApcCompatSession*>(handle);
442 }
443 
444 const ApcCompatServiceHandle INVALID_SERVICE_HANDLE = nullptr;
445