Add support for confirmation APIs.

This code implements new keystore APIs for confirmations.

Also add new 'confirmation' verb to the keystore_cli_v2 command to be
used for testing confirmations. It will block until there's a
callback. Example invocations:

 phone:/ # keystore_cli_v2 confirmation --prompt_text="Hello World" --extra_data=010203 --ui_options=1,2,3
 Waiting for prompt to complete - use Ctrl+C to abort...
 Confirmation prompt completed
 responseCode = 0
 dataThatWasConfirmed[30] = {0xa2, 0x66, 0x70, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x6b, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x65, 0x65, 0x78, 0x74, 0x72, 0x61, 0x43, 0x01, 0x02, 0x03}
 phone:/ #

If a prompt is already being shown, the |OperationPending| return code
(code 3) is returned:

 phone:/ # keystore_cli_v2 confirmation --prompt_text="Hello World" --extra_data=010203 --ui_options=1,2,3
 Presenting confirmation prompt failed with return code 3.

Canceling a prompt:

 phone:/# keystore_cli_v2 confirmation --prompt_text="Hello World" --extra_data=010203 --cancel_after=1.5
 Sleeping 1.5 seconds before canceling prompt...
 Waiting for prompt to complete - use Ctrl+C to abort...
 Confirmation prompt completed
 responseCode = 2
 dataThatWasConfirmed[0] = {}

Bug: 63928580
Test: Manually tested.
Change-Id: Ida14706ad066d5350b9081eb7821c7b1a1472dd2
diff --git a/keystore/confirmation_manager.cpp b/keystore/confirmation_manager.cpp
new file mode 100644
index 0000000..d8c5378
--- /dev/null
+++ b/keystore/confirmation_manager.cpp
@@ -0,0 +1,195 @@
+/*
+ * 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/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();
+    }
+
+    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();
+
+    finalizeTransaction(ConfirmationResponseCode::Aborted, {}, true);
+
+    *aidl_return = static_cast<int32_t>(ConfirmationResponseCode::OK);
+    return Status::ok();
+}
+
+void ConfirmationManager::finalizeTransaction(ConfirmationResponseCode responseCode,
+                                              hidl_vec<uint8_t> dataThatWasConfirmed,
+                                              bool callAbortOnHal) {
+    // Note that confirmationUI->abort() may make the remote HAL process do an IPC call back
+    // into our process resulting in confirmationResultCallback() to be called... this in turn
+    // calls finalizeTransaction(). So we have to be careful a) not holding any locks;
+    // and b) ensure state has been cleared; before doing this...
+
+    mMutex.lock();
+    sp<IBinder> listener = mCurrentListener;
+    if (mCurrentListener != nullptr) {
+        mCurrentListener->unlinkToDeath(mDeathRecipient);
+        mCurrentListener = nullptr;
+    }
+    sp<IConfirmationUI> confirmationUI = mCurrentConfirmationUI;
+    if (mCurrentConfirmationUI != nullptr) {
+        mCurrentConfirmationUI->unlinkToDeath(this);
+        mCurrentConfirmationUI = nullptr;
+    }
+    mMutex.unlock();
+
+    // Tell the HAL to shut down the confirmation dialog, if requested.
+    if (confirmationUI != nullptr && callAbortOnHal) {
+        confirmationUI->abort();
+    }
+
+    // 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, false);
+    lock_guard<mutex> lock(mMutex);
+    mLatestConfirmationToken = confirmationToken;
+    return Return<void>();
+}
+
+// Called by keystore main thread.
+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");
+        finalizeTransaction(ConfirmationResponseCode::SystemError, {}, true);
+    } 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, {}, false);
+}
+
+}  // namespace keystore