Keystore 2.0: Implement APC service.

This patch implements the Android Protected Confirmation service in
Keystore 2.0. This includes a C++ wrapper around the HIDL confirmationui
interface which will stay a HIDL interface for now.
This patch also includes the new AIDL specification.

This patch lacks death listener registration b/176491050.

Bug: 159341464
Bug: 173546269
Test: None
Change-Id: Ida4af108e86b538ab64d1dea4809cfa3b36f74cd
diff --git a/keystore2/apc_compat/apc_compat.cpp b/keystore2/apc_compat/apc_compat.cpp
new file mode 100644
index 0000000..08a8e45
--- /dev/null
+++ b/keystore2/apc_compat/apc_compat.cpp
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#include "apc_compat.hpp"
+#include <android-base/logging.h>
+#include <android/hardware/confirmationui/1.0/IConfirmationUI.h>
+#include <hwbinder/IBinder.h>
+
+#include <memory>
+#include <string>
+#include <thread>
+#include <vector>
+
+#define LOG_TAG "keystore2_apc_compat"
+
+namespace keystore2 {
+
+using android::sp;
+using android::hardware::hidl_death_recipient;
+using android::hardware::hidl_vec;
+using android::hardware::Return;
+using android::hardware::Status;
+using android::hardware::confirmationui::V1_0::IConfirmationResultCallback;
+using android::hardware::confirmationui::V1_0::IConfirmationUI;
+using android::hardware::confirmationui::V1_0::ResponseCode;
+using android::hardware::confirmationui::V1_0::UIOption;
+
+static uint32_t responseCode2Compat(ResponseCode rc) {
+    switch (rc) {
+    case ResponseCode::OK:
+        return APC_COMPAT_ERROR_OK;
+    case ResponseCode::Canceled:
+        return APC_COMPAT_ERROR_CANCELLED;
+    case ResponseCode::Aborted:
+        return APC_COMPAT_ERROR_ABORTED;
+    case ResponseCode::OperationPending:
+        return APC_COMPAT_ERROR_OPERATION_PENDING;
+    case ResponseCode::Ignored:
+        return APC_COMPAT_ERROR_IGNORED;
+    case ResponseCode::SystemError:
+    case ResponseCode::Unimplemented:
+    case ResponseCode::Unexpected:
+    case ResponseCode::UIError:
+    case ResponseCode::UIErrorMissingGlyph:
+    case ResponseCode::UIErrorMessageTooLong:
+    case ResponseCode::UIErrorMalformedUTF8Encoding:
+    default:
+        return APC_COMPAT_ERROR_SYSTEM_ERROR;
+    }
+}
+
+class ConfuiCompatSession : public IConfirmationResultCallback, public hidl_death_recipient {
+  public:
+    static sp<ConfuiCompatSession>* tryGetService() {
+        sp<IConfirmationUI> service = IConfirmationUI::tryGetService();
+        if (service) {
+            return new sp(new ConfuiCompatSession(std::move(service)));
+        } else {
+            return nullptr;
+        }
+    }
+
+    uint32_t promptUserConfirmation(ApcCompatCallback callback, const char* prompt_text,
+                                    const uint8_t* extra_data, size_t extra_data_size,
+                                    const char* locale, ApcCompatUiOptions ui_options) {
+        std::string hidl_prompt(prompt_text);
+        std::vector<uint8_t> hidl_extra(extra_data, extra_data + extra_data_size);
+        std::string hidl_locale(locale);
+        std::vector<UIOption> hidl_ui_options;
+        if (ui_options.inverted) {
+            hidl_ui_options.push_back(UIOption::AccessibilityInverted);
+        }
+        if (ui_options.magnified) {
+            hidl_ui_options.push_back(UIOption::AccessibilityMagnified);
+        }
+        auto lock = std::lock_guard(callback_lock_);
+        if (callback_.result != nullptr) {
+            return APC_COMPAT_ERROR_OPERATION_PENDING;
+        }
+        auto err = service_->linkToDeath(sp(this), 0);
+        if (!err.isOk()) {
+            LOG(ERROR) << "Communication error: promptUserConfirmation: "
+                          "Trying to register death recipient: "
+                       << err.description();
+            return APC_COMPAT_ERROR_SYSTEM_ERROR;
+        }
+
+        auto rc = service_->promptUserConfirmation(sp(this), hidl_prompt, hidl_extra, hidl_locale,
+                                                   hidl_ui_options);
+        if (!rc.isOk()) {
+            LOG(ERROR) << "Communication error: promptUserConfirmation: " << rc.description();
+        }
+        if (rc == ResponseCode::OK) {
+            callback_ = callback;
+        }
+        return responseCode2Compat(rc.withDefault(ResponseCode::SystemError));
+    }
+
+    void abort() { service_->abort(); }
+
+    void
+    finalize(ResponseCode responseCode,
+             std::optional<std::reference_wrapper<const hidl_vec<uint8_t>>> dataConfirmed,
+             std::optional<std::reference_wrapper<const hidl_vec<uint8_t>>> confirmationToken) {
+        ApcCompatCallback callback;
+        {
+            auto lock = std::lock_guard(callback_lock_);
+            // Calling the callback consumes the callback data structure. We have to make
+            // sure that it can only be called once.
+            callback = callback_;
+            callback_ = {nullptr, nullptr};
+            // Unlock the callback_lock_ here. It must never be held while calling the callback.
+        }
+
+        if (callback.result != nullptr) {
+            service_->unlinkToDeath(sp(this));
+
+            size_t dataConfirmedSize = 0;
+            const uint8_t* dataConfirmedPtr = nullptr;
+            size_t confirmationTokenSize = 0;
+            const uint8_t* confirmationTokenPtr = nullptr;
+            if (responseCode == ResponseCode::OK) {
+                if (dataConfirmed) {
+                    dataConfirmedPtr = dataConfirmed->get().data();
+                    dataConfirmedSize = dataConfirmed->get().size();
+                }
+                if (dataConfirmed) {
+                    confirmationTokenPtr = confirmationToken->get().data();
+                    confirmationTokenSize = confirmationToken->get().size();
+                }
+            }
+            callback.result(callback.data, responseCode2Compat(responseCode), dataConfirmedPtr,
+                            dataConfirmedSize, confirmationTokenPtr, confirmationTokenSize);
+        }
+    }
+
+    // IConfirmationResultCallback overrides:
+    android::hardware::Return<void> result(ResponseCode responseCode,
+                                           const hidl_vec<uint8_t>& dataConfirmed,
+                                           const hidl_vec<uint8_t>& confirmationToken) override {
+        finalize(responseCode, dataConfirmed, confirmationToken);
+        return Status::ok();
+    };
+
+    void serviceDied(uint64_t /* cookie */,
+                     const ::android::wp<::android::hidl::base::V1_0::IBase>& /* who */) override {
+        finalize(ResponseCode::SystemError, {}, {});
+    }
+
+  private:
+    ConfuiCompatSession(sp<IConfirmationUI> service)
+        : service_(service), callback_{nullptr, nullptr} {}
+    sp<IConfirmationUI> service_;
+
+    // The callback_lock_ protects the callback_ field against concurrent modification.
+    // IMPORTANT: It must never be held while calling the call back.
+    std::mutex callback_lock_;
+    ApcCompatCallback callback_;
+};
+
+}  // namespace keystore2
+
+using namespace keystore2;
+
+ApcCompatServiceHandle tryGetUserConfirmationService() {
+    return reinterpret_cast<ApcCompatServiceHandle>(ConfuiCompatSession::tryGetService());
+}
+
+uint32_t 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) {
+    auto session = reinterpret_cast<sp<ConfuiCompatSession>*>(handle);
+    return (*session)->promptUserConfirmation(callback, prompt_text, extra_data, extra_data_size,
+                                              locale, ui_options);
+}
+
+void abortUserConfirmation(ApcCompatServiceHandle handle) {
+    auto session = reinterpret_cast<sp<ConfuiCompatSession>*>(handle);
+    (*session)->abort();
+}
+
+void closeUserConfirmationService(ApcCompatServiceHandle handle) {
+    // Closing the handle implicitly aborts an ongoing sessions.
+    // Note that a resulting callback is still safely conducted, because we only delete a
+    // StrongPointer below. libhwbinder still owns another StrongPointer to this session.
+    abortUserConfirmation(handle);
+    delete reinterpret_cast<sp<ConfuiCompatSession>*>(handle);
+}
+
+const ApcCompatServiceHandle INVALID_SERVICE_HANDLE = nullptr;