16ae65c2ab
Cancelling an APC request from the app side must lead to a callback to unblock the caller. Bug: 138655142 Bug: 148411844 Test: atest confirmationui_invocation_test Change-Id: If71ffc7d3d75dde6f0217ccdb003569149947ec8
214 lines
7.9 KiB
C++
214 lines
7.9 KiB
C++
/*
|
|
* Copyright (C) 2017 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.
|
|
*/
|
|
|
|
#define LOG_TAG "ConfirmationManager"
|
|
|
|
#include "confirmation_manager.h"
|
|
|
|
#include <android/hardware/confirmationui/1.0/IConfirmationResultCallback.h>
|
|
#include <android/hardware/confirmationui/1.0/IConfirmationUI.h>
|
|
#include <android/hardware/confirmationui/1.0/types.h>
|
|
#include <android/security/BpConfirmationPromptCallback.h>
|
|
#include <binder/BpBinder.h>
|
|
#include <binder/IPCThreadState.h>
|
|
#include <binder/Parcel.h>
|
|
|
|
#include "keystore_aidl_hidl_marshalling_utils.h"
|
|
|
|
namespace keystore {
|
|
|
|
using android::IBinder;
|
|
using android::sp;
|
|
using android::String16;
|
|
using android::String8;
|
|
using android::wp;
|
|
using android::binder::Status;
|
|
using android::hardware::hidl_vec;
|
|
using android::hardware::Return;
|
|
using android::hardware::confirmationui::V1_0::IConfirmationResultCallback;
|
|
using android::hardware::confirmationui::V1_0::IConfirmationUI;
|
|
using android::hardware::confirmationui::V1_0::UIOption;
|
|
|
|
using android::security::BpConfirmationPromptCallback;
|
|
using std::lock_guard;
|
|
using std::mutex;
|
|
using std::vector;
|
|
|
|
ConfirmationManager::ConfirmationManager(IBinder::DeathRecipient* deathRecipient)
|
|
: IConfirmationResultCallback(), mDeathRecipient(deathRecipient) {}
|
|
|
|
// Called by keystore main thread.
|
|
Status ConfirmationManager::presentConfirmationPrompt(const sp<IBinder>& listener,
|
|
const String16& promptText,
|
|
const hidl_vec<uint8_t>& extraData,
|
|
const String16& locale, int uiOptionsAsFlags,
|
|
int32_t* aidl_return) {
|
|
lock_guard<mutex> lock(mMutex);
|
|
|
|
if (mCurrentListener != nullptr) {
|
|
*aidl_return = static_cast<int32_t>(ConfirmationResponseCode::OperationPending);
|
|
return Status::ok();
|
|
}
|
|
|
|
sp<IConfirmationUI> confirmationUI = IConfirmationUI::tryGetService();
|
|
if (confirmationUI == nullptr) {
|
|
ALOGW("Error getting confirmationUI service\n");
|
|
*aidl_return = static_cast<int32_t>(ConfirmationResponseCode::Unimplemented);
|
|
return Status::ok();
|
|
}
|
|
|
|
uid_t callingUid = android::IPCThreadState::self()->getCallingUid();
|
|
if (!mRateLimiting.tryPrompt(callingUid)) {
|
|
*aidl_return = static_cast<int32_t>(ConfirmationResponseCode::SystemError);
|
|
return Status::ok();
|
|
}
|
|
|
|
String8 promptText8(promptText);
|
|
String8 locale8(locale);
|
|
vector<UIOption> uiOptionsVector;
|
|
for (int n = 0; n < 32; n++) {
|
|
if (uiOptionsAsFlags & (1 << n)) {
|
|
uiOptionsVector.push_back(UIOption(n));
|
|
}
|
|
}
|
|
ConfirmationResponseCode responseCode;
|
|
responseCode = confirmationUI->promptUserConfirmation(sp<IConfirmationResultCallback>(this),
|
|
promptText8.string(), extraData,
|
|
locale8.string(), uiOptionsVector);
|
|
if (responseCode != ConfirmationResponseCode::OK) {
|
|
ALOGW("Unexpecxted responseCode %d from promptUserConfirmation\n", responseCode);
|
|
*aidl_return = static_cast<int32_t>(responseCode);
|
|
return Status::ok();
|
|
}
|
|
|
|
listener->linkToDeath(mDeathRecipient);
|
|
confirmationUI->linkToDeath(this, 0);
|
|
mCurrentListener = listener;
|
|
mCurrentConfirmationUI = confirmationUI;
|
|
|
|
*aidl_return = static_cast<int32_t>(ConfirmationResponseCode::OK);
|
|
return Status::ok();
|
|
}
|
|
|
|
// Called by keystore main thread.
|
|
Status ConfirmationManager::cancelConfirmationPrompt(const sp<IBinder>& listener,
|
|
int32_t* aidl_return) {
|
|
mMutex.lock();
|
|
if (mCurrentListener != listener) {
|
|
// If the prompt was displayed by another application, return
|
|
// OperationPending.
|
|
mMutex.unlock();
|
|
*aidl_return = static_cast<int32_t>(ConfirmationResponseCode::OperationPending);
|
|
return Status::ok();
|
|
}
|
|
mMutex.unlock();
|
|
|
|
cancelPrompt();
|
|
|
|
*aidl_return = static_cast<int32_t>(ConfirmationResponseCode::OK);
|
|
return Status::ok();
|
|
}
|
|
|
|
void ConfirmationManager::cancelPrompt() {
|
|
mMutex.lock();
|
|
mRateLimiting.cancelPrompt();
|
|
sp<IConfirmationUI> confirmationUI = mCurrentConfirmationUI;
|
|
mMutex.unlock();
|
|
if (confirmationUI != nullptr) {
|
|
confirmationUI->abort();
|
|
}
|
|
}
|
|
|
|
// Called by keystore main thread.
|
|
Status ConfirmationManager::isConfirmationPromptSupported(bool* aidl_return) {
|
|
sp<IConfirmationUI> confirmationUI = IConfirmationUI::tryGetService();
|
|
if (confirmationUI == nullptr) {
|
|
ALOGW("Error getting confirmationUI service\n");
|
|
*aidl_return = false;
|
|
return Status::ok();
|
|
}
|
|
|
|
*aidl_return = true;
|
|
return Status::ok();
|
|
}
|
|
|
|
void ConfirmationManager::finalizeTransaction(ConfirmationResponseCode responseCode,
|
|
hidl_vec<uint8_t> dataThatWasConfirmed) {
|
|
mMutex.lock();
|
|
mRateLimiting.processResult(responseCode);
|
|
sp<IBinder> listener = mCurrentListener;
|
|
if (mCurrentListener != nullptr) {
|
|
mCurrentListener->unlinkToDeath(mDeathRecipient);
|
|
mCurrentListener = nullptr;
|
|
}
|
|
if (mCurrentConfirmationUI != nullptr) {
|
|
mCurrentConfirmationUI->unlinkToDeath(this);
|
|
mCurrentConfirmationUI = nullptr;
|
|
}
|
|
mMutex.unlock();
|
|
|
|
// Deliver result to the application that started the operation.
|
|
if (listener != nullptr) {
|
|
sp<BpConfirmationPromptCallback> obj = new BpConfirmationPromptCallback(listener);
|
|
Status status = obj->onConfirmationPromptCompleted(static_cast<int32_t>(responseCode),
|
|
dataThatWasConfirmed);
|
|
if (!status.isOk()) {
|
|
ALOGW("Error sending onConfirmationPromptCompleted - status: %s\n",
|
|
status.toString8().c_str());
|
|
}
|
|
}
|
|
}
|
|
|
|
// Called by hwbinder thread (not keystore main thread).
|
|
Return<void> ConfirmationManager::result(ConfirmationResponseCode responseCode,
|
|
const hidl_vec<uint8_t>& dataThatWasConfirmed,
|
|
const hidl_vec<uint8_t>& confirmationToken) {
|
|
finalizeTransaction(responseCode, dataThatWasConfirmed);
|
|
lock_guard<mutex> lock(mMutex);
|
|
mLatestConfirmationToken = confirmationToken;
|
|
return Return<void>();
|
|
}
|
|
|
|
// Called by keystore main thread or keymaster worker
|
|
hidl_vec<uint8_t> ConfirmationManager::getLatestConfirmationToken() {
|
|
lock_guard<mutex> lock(mMutex);
|
|
return mLatestConfirmationToken;
|
|
}
|
|
|
|
void ConfirmationManager::binderDied(const wp<IBinder>& who) {
|
|
// This is also called for other binders so need to check it's for
|
|
// us before acting on it.
|
|
mMutex.lock();
|
|
if (who == mCurrentListener) {
|
|
// Clear this so we don't call back into the already dead
|
|
// binder in finalizeTransaction().
|
|
mCurrentListener->unlinkToDeath(mDeathRecipient);
|
|
mCurrentListener = nullptr;
|
|
mMutex.unlock();
|
|
ALOGW("The process which requested the confirmation dialog died.\n");
|
|
cancelPrompt();
|
|
} else {
|
|
mMutex.unlock();
|
|
}
|
|
}
|
|
|
|
void ConfirmationManager::serviceDied(uint64_t /* cookie */,
|
|
const wp<android::hidl::base::V1_0::IBase>& /* who */) {
|
|
ALOGW("The ConfirmationUI HAL died.\n");
|
|
finalizeTransaction(ConfirmationResponseCode::SystemError, {});
|
|
}
|
|
|
|
} // namespace keystore
|