blob: acca304553f037395ff0a9b877f67911751956b9 [file] [log] [blame]
David Zeuthenc6eb7cd2017-11-27 11:33:55 -05001/*
2 * Copyright (C) 2017 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#define LOG_TAG "ConfirmationManager"
18
19#include "confirmation_manager.h"
20
21#include <android/hardware/confirmationui/1.0/IConfirmationResultCallback.h>
22#include <android/hardware/confirmationui/1.0/IConfirmationUI.h>
23#include <android/hardware/confirmationui/1.0/types.h>
24#include <android/security/BpConfirmationPromptCallback.h>
25#include <binder/BpBinder.h>
26#include <binder/Parcel.h>
27
28#include "keystore_aidl_hidl_marshalling_utils.h"
29
30namespace keystore {
31
32using android::IBinder;
33using android::sp;
34using android::String16;
35using android::String8;
36using android::wp;
37using android::binder::Status;
38using android::hardware::hidl_vec;
39using android::hardware::Return;
40using android::hardware::confirmationui::V1_0::IConfirmationResultCallback;
41using android::hardware::confirmationui::V1_0::IConfirmationUI;
42using android::hardware::confirmationui::V1_0::UIOption;
43
44using android::security::BpConfirmationPromptCallback;
45using std::lock_guard;
46using std::mutex;
47using std::vector;
48
49ConfirmationManager::ConfirmationManager(IBinder::DeathRecipient* deathRecipient)
50 : IConfirmationResultCallback(), mDeathRecipient(deathRecipient) {}
51
52// Called by keystore main thread.
53Status ConfirmationManager::presentConfirmationPrompt(const sp<IBinder>& listener,
54 const String16& promptText,
55 const hidl_vec<uint8_t>& extraData,
56 const String16& locale, int uiOptionsAsFlags,
57 int32_t* aidl_return) {
58 lock_guard<mutex> lock(mMutex);
59
60 if (mCurrentListener != nullptr) {
61 *aidl_return = static_cast<int32_t>(ConfirmationResponseCode::OperationPending);
62 return Status::ok();
63 }
64
65 sp<IConfirmationUI> confirmationUI = IConfirmationUI::tryGetService();
66 if (confirmationUI == nullptr) {
67 ALOGW("Error getting confirmationUI service\n");
68 *aidl_return = static_cast<int32_t>(ConfirmationResponseCode::Unimplemented);
69 return Status::ok();
70 }
71
72 String8 promptText8(promptText);
73 String8 locale8(locale);
74 vector<UIOption> uiOptionsVector;
75 for (int n = 0; n < 32; n++) {
76 if (uiOptionsAsFlags & (1 << n)) {
77 uiOptionsVector.push_back(UIOption(n));
78 }
79 }
80 ConfirmationResponseCode responseCode;
81 responseCode = confirmationUI->promptUserConfirmation(sp<IConfirmationResultCallback>(this),
82 promptText8.string(), extraData,
83 locale8.string(), uiOptionsVector);
84 if (responseCode != ConfirmationResponseCode::OK) {
85 ALOGW("Unexpecxted responseCode %d from promptUserConfirmation\n", responseCode);
86 *aidl_return = static_cast<int32_t>(responseCode);
87 return Status::ok();
88 }
89
90 listener->linkToDeath(mDeathRecipient);
91 confirmationUI->linkToDeath(this, 0);
92 mCurrentListener = listener;
93 mCurrentConfirmationUI = confirmationUI;
94
95 *aidl_return = static_cast<int32_t>(ConfirmationResponseCode::OK);
96 return Status::ok();
97}
98
99// Called by keystore main thread.
100Status ConfirmationManager::cancelConfirmationPrompt(const sp<IBinder>& listener,
101 int32_t* aidl_return) {
102 mMutex.lock();
103 if (mCurrentListener != listener) {
104 // If the prompt was displayed by another application, return
105 // OperationPending.
106 mMutex.unlock();
107 *aidl_return = static_cast<int32_t>(ConfirmationResponseCode::OperationPending);
108 return Status::ok();
109 }
110 mMutex.unlock();
111
112 finalizeTransaction(ConfirmationResponseCode::Aborted, {}, true);
113
114 *aidl_return = static_cast<int32_t>(ConfirmationResponseCode::OK);
115 return Status::ok();
116}
117
David Zeuthen1a492312018-02-26 11:00:30 -0500118// Called by keystore main thread.
119Status ConfirmationManager::isConfirmationPromptSupported(bool* aidl_return) {
120 sp<IConfirmationUI> confirmationUI = IConfirmationUI::tryGetService();
121 if (confirmationUI == nullptr) {
122 ALOGW("Error getting confirmationUI service\n");
123 *aidl_return = false;
124 return Status::ok();
125 }
126
127 *aidl_return = true;
128 return Status::ok();
129}
130
David Zeuthenc6eb7cd2017-11-27 11:33:55 -0500131void ConfirmationManager::finalizeTransaction(ConfirmationResponseCode responseCode,
132 hidl_vec<uint8_t> dataThatWasConfirmed,
133 bool callAbortOnHal) {
134 // Note that confirmationUI->abort() may make the remote HAL process do an IPC call back
135 // into our process resulting in confirmationResultCallback() to be called... this in turn
136 // calls finalizeTransaction(). So we have to be careful a) not holding any locks;
137 // and b) ensure state has been cleared; before doing this...
138
139 mMutex.lock();
140 sp<IBinder> listener = mCurrentListener;
141 if (mCurrentListener != nullptr) {
142 mCurrentListener->unlinkToDeath(mDeathRecipient);
143 mCurrentListener = nullptr;
144 }
145 sp<IConfirmationUI> confirmationUI = mCurrentConfirmationUI;
146 if (mCurrentConfirmationUI != nullptr) {
147 mCurrentConfirmationUI->unlinkToDeath(this);
148 mCurrentConfirmationUI = nullptr;
149 }
150 mMutex.unlock();
151
152 // Tell the HAL to shut down the confirmation dialog, if requested.
153 if (confirmationUI != nullptr && callAbortOnHal) {
154 confirmationUI->abort();
155 }
156
157 // Deliver result to the application that started the operation.
158 if (listener != nullptr) {
159 sp<BpConfirmationPromptCallback> obj = new BpConfirmationPromptCallback(listener);
160 Status status = obj->onConfirmationPromptCompleted(static_cast<int32_t>(responseCode),
161 dataThatWasConfirmed);
162 if (!status.isOk()) {
163 ALOGW("Error sending onConfirmationPromptCompleted - status: %s\n",
164 status.toString8().c_str());
165 }
166 }
167}
168
169// Called by hwbinder thread (not keystore main thread).
170Return<void> ConfirmationManager::result(ConfirmationResponseCode responseCode,
171 const hidl_vec<uint8_t>& dataThatWasConfirmed,
172 const hidl_vec<uint8_t>& confirmationToken) {
173 finalizeTransaction(responseCode, dataThatWasConfirmed, false);
174 lock_guard<mutex> lock(mMutex);
175 mLatestConfirmationToken = confirmationToken;
176 return Return<void>();
177}
178
179// Called by keystore main thread.
180hidl_vec<uint8_t> ConfirmationManager::getLatestConfirmationToken() {
181 lock_guard<mutex> lock(mMutex);
182 return mLatestConfirmationToken;
183}
184
185void ConfirmationManager::binderDied(const wp<IBinder>& who) {
186 // This is also called for other binders so need to check it's for
187 // us before acting on it.
188 mMutex.lock();
189 if (who == mCurrentListener) {
190 // Clear this so we don't call back into the already dead
191 // binder in finalizeTransaction().
192 mCurrentListener->unlinkToDeath(mDeathRecipient);
193 mCurrentListener = nullptr;
194 mMutex.unlock();
195 ALOGW("The process which requested the confirmation dialog died.\n");
196 finalizeTransaction(ConfirmationResponseCode::SystemError, {}, true);
197 } else {
198 mMutex.unlock();
199 }
200}
201
202void ConfirmationManager::serviceDied(uint64_t /* cookie */,
203 const wp<android::hidl::base::V1_0::IBase>& /* who */) {
204 ALOGW("The ConfirmationUI HAL died.\n");
205 finalizeTransaction(ConfirmationResponseCode::SystemError, {}, false);
206}
207
208} // namespace keystore