Merge "camera: Add physical camera metadata in CaptureResult"
diff --git a/authsecret/1.0/IAuthSecret.hal b/authsecret/1.0/IAuthSecret.hal
index d2cb5da..6b573b3 100644
--- a/authsecret/1.0/IAuthSecret.hal
+++ b/authsecret/1.0/IAuthSecret.hal
@@ -24,25 +24,23 @@
  */
 interface IAuthSecret {
     /**
-     * When the primary user correctly enters their credential, this method is
-     * passed a secret derived from that credential to prove that their
-     * credential is known.
+     * When the primary user is unlocked, this method is passed a secret to
+     * prove that is has been successfully unlocked. The primary user can either
+     * be unlocked by a person entering their credential or by another party
+     * using an escrow token e.g. a device administrator.
      *
      * The first time this is called, the secret must be used to provision state
-     * that depends on the primary user's credential. The same secret is passed
-     * on each call until a factory reset after which there must be a new
-     * secret.
+     * that depends on the primary user's secret. The same secret must be passed
+     * on each call until the next factory reset.
      *
-     * The secret must be at lesat 16 bytes.
+     * Upon factory reset, any dependence on the secret must be removed as that
+     * secret is now lost and must never be derived again. A new secret must be
+     * created for the new primary user which must be used to newly provision
+     * state the first time this method is called after factory reset.
+     *
+     * The secret must be at least 16 bytes.
      *
      * @param secret blob derived from the primary user's credential.
      */
     primaryUserCredential(vec<uint8_t> secret);
-
-    /**
-     * Called from recovery during factory reset. The secret is now lost and can
-     * no longer be derived. Any data linked to the secret must be destroyed and
-     * any dependence on the secret must be removed.
-     */
-    factoryReset();
 };
diff --git a/authsecret/1.0/default/AuthSecret.cpp b/authsecret/1.0/default/AuthSecret.cpp
index 46a3ec1..f9271e9 100644
--- a/authsecret/1.0/default/AuthSecret.cpp
+++ b/authsecret/1.0/default/AuthSecret.cpp
@@ -29,16 +29,12 @@
     return Void();
 }
 
-Return<void> AuthSecret::factoryReset() {
-    // Clear all dependency on the secret.
-    //
-    // With the example of updating a security module, the stored value must be
-    // cleared so that the new primary user enrolled as the approver of updates.
-    //
-    // This implementation does nothing as there is no dependence on the secret.
-
-    return Void();
-}
+// Note: on factory reset, clear all dependency on the secret.
+//
+// With the example of updating a security module, the stored value must be
+// cleared so that the new primary user enrolled as the approver of updates.
+//
+// This implementation does nothing as there is no dependence on the secret.
 
 }  // namespace implementation
 }  // namespace V1_0
diff --git a/authsecret/1.0/default/AuthSecret.h b/authsecret/1.0/default/AuthSecret.h
index edb49b8..387fa67 100644
--- a/authsecret/1.0/default/AuthSecret.h
+++ b/authsecret/1.0/default/AuthSecret.h
@@ -22,7 +22,6 @@
 struct AuthSecret : public IAuthSecret {
     // Methods from ::android::hardware::authsecret::V1_0::IAuthSecret follow.
     Return<void> primaryUserCredential(const hidl_vec<uint8_t>& secret) override;
-    Return<void> factoryReset() override;
 
     // Methods from ::android::hidl::base::V1_0::IBase follow.
 };
diff --git a/authsecret/1.0/vts/functional/VtsHalAuthSecretV1_0TargetTest.cpp b/authsecret/1.0/vts/functional/VtsHalAuthSecretV1_0TargetTest.cpp
index b0cbd91..a610a75 100644
--- a/authsecret/1.0/vts/functional/VtsHalAuthSecretV1_0TargetTest.cpp
+++ b/authsecret/1.0/vts/functional/VtsHalAuthSecretV1_0TargetTest.cpp
@@ -30,68 +30,42 @@
     virtual void SetUp() override {
         authsecret = ::testing::VtsHalHidlTargetTestBase::getService<IAuthSecret>();
         ASSERT_NE(authsecret, nullptr);
-        authsecret->factoryReset();
+
+        // All tests must enroll the correct secret first as this cannot be changed
+        // without a factory reset and the order of tests could change.
+        authsecret->primaryUserCredential(CORRECT_SECRET);
     }
 
     sp<IAuthSecret> authsecret;
+    hidl_vec<uint8_t> CORRECT_SECRET{61, 93, 124, 240, 5, 0, 7, 201, 9, 129, 11, 12, 0, 14, 0, 16};
+    hidl_vec<uint8_t> WRONG_SECRET{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
 };
 
 /* Provision the primary user with a secret. */
 TEST_F(AuthSecretHidlTest, provisionPrimaryUserCredential) {
-    hidl_vec<uint8_t> secret{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
-    authsecret->primaryUserCredential(secret);
-}
-
-/* Provision the primary user with a large secret. */
-TEST_F(AuthSecretHidlTest, provisionPrimaryUserCredentialWithLargeSecret) {
-    hidl_vec<uint8_t> secret{89,  233, 52,  29,  130, 210, 229, 170, 124, 102, 56,  238, 198,
-                             199, 246, 152, 185, 123, 155, 215, 29,  252, 30,  70,  118, 29,
-                             149, 36,  222, 203, 163, 7,   72,  56,  247, 19,  198, 76,  71,
-                             37,  120, 201, 220, 70,  150, 18,  23,  22,  236, 57,  184, 86,
-                             190, 122, 210, 207, 74,  51,  222, 157, 74,  196, 86,  208};
-    authsecret->primaryUserCredential(secret);
+    // Secret provisioned by SetUp()
 }
 
 /* Provision the primary user with a secret and pass the secret again. */
 TEST_F(AuthSecretHidlTest, provisionPrimaryUserCredentialAndPassAgain) {
-    hidl_vec<uint8_t> secret{64, 2, 3, 0, 5, 6, 7, 172, 9, 10, 11, 255, 13, 14, 15, 83};
-    authsecret->primaryUserCredential(secret);
-    authsecret->primaryUserCredential(secret);
+    // Secret provisioned by SetUp()
+    authsecret->primaryUserCredential(CORRECT_SECRET);
 }
 
 /* Provision the primary user with a secret and pass the secret again repeatedly. */
 TEST_F(AuthSecretHidlTest, provisionPrimaryUserCredentialAndPassAgainMultipleTimes) {
-    hidl_vec<uint8_t> secret{1, 2, 34, 4, 5, 6, 7, 8, 9, 105, 11, 12, 13, 184, 15, 16};
-    authsecret->primaryUserCredential(secret);
+    // Secret provisioned by SetUp()
     constexpr int N = 5;
     for (int i = 0; i < N; ++i) {
-        authsecret->primaryUserCredential(secret);
+        authsecret->primaryUserCredential(CORRECT_SECRET);
     }
 }
 
-/* Factory reset before provisioning the primary user with a secret. */
-TEST_F(AuthSecretHidlTest, factoryResetWithoutProvisioningPrimaryUserCredential) {
-    authsecret->factoryReset();
-}
-
-/* Provision the primary user with a secret then factory reset. */
-TEST_F(AuthSecretHidlTest, provisionPrimaryUserCredentialAndFactoryReset) {
-    hidl_vec<uint8_t> secret{1, 24, 124, 240, 5, 6, 7, 8, 9, 13, 11, 12, 189, 14, 195, 16};
-    authsecret->primaryUserCredential(secret);
-    authsecret->factoryReset();
-}
-
-/* Provision the primary differently after factory reset. */
-TEST_F(AuthSecretHidlTest, provisionPrimaryUserCredentialDifferentlyAfterFactoryReset) {
-    {
-        hidl_vec<uint8_t> secret1{19, 0, 65, 20, 65, 12, 7, 8, 9, 13, 29, 12, 189, 32, 195, 16};
-        authsecret->primaryUserCredential(secret1);
-    }
-
-    authsecret->factoryReset();
-
-    {
-        hidl_vec<uint8_t> secret2{61, 93, 124, 240, 5, 0, 7, 201, 9, 129, 11, 12, 0, 14, 0, 16};
-        authsecret->primaryUserCredential(secret2);
-    }
+/* Provision the primary user with a secret and then pass the wrong secret. This
+ * should never happen and is an framework bug if it does. As the secret is
+ * wrong, the HAL implementation may not be able to function correctly but it
+ * should fail gracefully. */
+TEST_F(AuthSecretHidlTest, provisionPrimaryUserCredentialAndWrongSecret) {
+    // Secret provisioned by SetUp()
+    authsecret->primaryUserCredential(WRONG_SECRET);
 }
diff --git a/confirmationui/1.0/Android.bp b/confirmationui/1.0/Android.bp
new file mode 100644
index 0000000..21acecb
--- /dev/null
+++ b/confirmationui/1.0/Android.bp
@@ -0,0 +1,27 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.confirmationui@1.0",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "IConfirmationResultCallback.hal",
+        "IConfirmationUI.hal",
+    ],
+    interfaces: [
+        "android.hardware.keymaster@4.0",
+        "android.hidl.base@1.0",
+    ],
+    types: [
+        "MessageSize",
+        "ResponseCode",
+        "TestKeyBits",
+        "TestModeCommands",
+        "UIOption",
+    ],
+    gen_java: false,
+}
+
diff --git a/confirmationui/1.0/IConfirmationResultCallback.hal b/confirmationui/1.0/IConfirmationResultCallback.hal
new file mode 100644
index 0000000..03a10cf
--- /dev/null
+++ b/confirmationui/1.0/IConfirmationResultCallback.hal
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+package android.hardware.confirmationui@1.0;
+
+/**
+ * Callback interface passed to IConfirmationUI::promptUserConfirmation().
+ * Informs the caller about the result of the prompt operation.
+ */
+interface IConfirmationResultCallback {
+    /**
+     * This callback is called by the confirmation provider when it stops prompting the user.
+     * Iff the user has confirmed the prompted text, error is ErrorCode::OK and the
+     * parameters formattedMessage and confirmationToken hold the values needed to request
+     * a signature from keymaster.
+     * In all other cases formattedMessage and confirmationToken must be of length 0.
+     *
+     * @param error - OK: IFF the user has confirmed the prompt.
+     *              - Canceled: If the user has pressed the cancel button.
+     *              - Aborted: If IConfirmationUI::abort() was called.
+     *              - SystemError: If an unexpected System error occurred that prevented the TUI
+     *                             from being shut down gracefully.
+     * @param formattedMessage holds the prompt text and extra data.
+     *                         The message is CBOR (RFC 7049) encoded and has the following format:
+     *                         CBOR_MAP{ "prompt", <promptText>, "extra", <extraData> }
+     *                         The message is a CBOR encoded map (type 5) with the keys
+     *                         "prompt" and "extra". The keys are encoded as CBOR text string
+     *                         (type 3). The value <promptText> is encoded as CBOR text string
+     *                         (type 3), and the value <extraData> is encoded as CBOR byte string
+     *                         (type 2). The map must have exactly one key value pair for each of
+     *                         the keys "prompt" and "extra". Other keys are not allowed.
+     *                         The value of "prompt" is given by the proptText argument to
+     *                         IConfirmationUI::promptUserConfirmation and must not be modified
+     *                         by the implementation.
+     *                         The value of "extra" is given by the extraData argument to
+     *                         IConfirmationUI::promptUserConfirmation and must not be modified
+     *                         or interpreted by the implementation.
+     *
+     * @param confirmationToken a 32-byte HMAC-SHA256 value, computed over
+     *                          "confirmation token" || <formattedMessage>
+     *                          i.e. the literal UTF-8 encoded string "confirmation token", without
+     *                          the "", concatenated with the formatted message as returned in the
+     *                          formattedMessage argument. The HMAC is keyed with a 256-bit secret
+     *                          which is shared with Keymaster. In test mode the test key MUST be
+     *                          used (see types.hal TestModeCommands and TestKeyBits).
+     */
+    result(ResponseCode error, vec<uint8_t> formattedMessage, vec<uint8_t> confirmationToken);
+};
diff --git a/confirmationui/1.0/IConfirmationUI.hal b/confirmationui/1.0/IConfirmationUI.hal
new file mode 100644
index 0000000..db8055d
--- /dev/null
+++ b/confirmationui/1.0/IConfirmationUI.hal
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ */
+
+package android.hardware.confirmationui@1.0;
+
+import android.hardware.keymaster@4.0::HardwareAuthToken;
+import IConfirmationResultCallback;
+
+interface IConfirmationUI {
+    /**
+     * Asynchronously initiates a confirmation UI dialog prompting the user to confirm a given text.
+     * The TUI prompt must be implemented in such a way that a positive response indicates with
+     * high confidence that a user has seen the given prompt text even if the Android framework
+     * including the kernel was compromised.
+     *
+     * @param resultCB Implementation of IResultCallback. Used by the implementation to report
+     *                 the result of the current pending user prompt.
+     *
+     * @param promptText UTF-8 encoded string which is to be presented to the user.
+     *
+     * @param extraData A binary blob that must be included in the formatted output message as is.
+     *                  It is opaque to the implementation. Implementations must neither interpret
+     *                  nor modify the content.
+     *
+     * @param locale String specifying the locale that must be used by the TUI dialog. The string
+     *                      is an IETF BCP 47 tag.
+     *
+     * @param uiOptions A set of uiOptions manipulating how the confirmation prompt is displayed.
+     *                  Refer to UIOption in types.hal for possible options.
+     *
+     * @return error  - OK: IFF the dialog was successfully started. In this case, and only in this
+     *                      case, the implementation must, eventually, call the callback to
+     *                      indicate completion.
+     *                - OperationPending: Is returned when the confirmation provider is currently
+     *                      in use.
+     *                - SystemError: An error occurred trying to communicate with the confirmation
+     *                      provider (e.g. trusted app).
+     *                - UIError: The confirmation provider encountered an issue with displaying
+     *                      the prompt text to the user.
+     */
+    promptUserConfirmation(IConfirmationResultCallback resultCB, string promptText,
+                           vec<uint8_t> extraData, string locale, vec<UIOption> uiOptions)
+        generates(ResponseCode error);
+
+    /**
+     * DeliverSecureInput is used by the framework to deliver a secure input event to the
+     * confirmation provider.
+     *
+     * VTS test mode:
+     * This function can be used to test certain code paths non-interactively. See TestModeCommands
+     * in types.hal for details.
+     *
+     * @param secureInputToken An authentication token as generated by Android authentication
+     *                         providers.
+     *
+     * @return error - Ignored: Unless used for testing (See TestModeCommands).
+     */
+    deliverSecureInputEvent(HardwareAuthToken secureInputToken)
+        generates(ResponseCode error);
+
+    /**
+     * Aborts a pending user prompt. This allows the framework to gracefully end a TUI dialog.
+     * If a TUI operation was pending the corresponding call back is informed with
+     * ErrorCode::Aborted.
+     */
+    abort();
+};
+
diff --git a/confirmationui/1.0/default/Android.bp b/confirmationui/1.0/default/Android.bp
new file mode 100644
index 0000000..10018e8
--- /dev/null
+++ b/confirmationui/1.0/default/Android.bp
@@ -0,0 +1,43 @@
+//
+// 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.
+//
+
+cc_binary {
+    name: "android.hardware.confirmationui@1.0-service",
+    init_rc: ["android.hardware.confirmationui@1.0-service.rc"],
+    vendor: true,
+    relative_install_path: "hw",
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+    ],
+    srcs: [
+        "service.cpp",
+        "ConfirmationUI.cpp",
+        "PlatformSpecifics.cpp",
+    ],
+    shared_libs: [
+        "android.hardware.confirmationui@1.0",
+        "android.hardware.confirmationui-support-lib",
+        "android.hardware.keymaster@4.0",
+        "libcrypto",
+        "libbase",
+        "libhidlbase",
+        "libhidltransport",
+        "liblog",
+        "libutils",
+    ],
+}
\ No newline at end of file
diff --git a/confirmationui/1.0/default/ConfirmationUI.cpp b/confirmationui/1.0/default/ConfirmationUI.cpp
new file mode 100644
index 0000000..f241a76
--- /dev/null
+++ b/confirmationui/1.0/default/ConfirmationUI.cpp
@@ -0,0 +1,66 @@
+/*
+**
+** Copyright 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.
+*/
+
+#include "ConfirmationUI.h"
+
+#include "PlatformSpecifics.h"
+
+#include <android/hardware/confirmationui/support/cbor.h>
+#include <android/hardware/confirmationui/support/confirmationui_utils.h>
+
+#include <android/hardware/confirmationui/1.0/generic/GenericOperation.h>
+
+#include <time.h>
+
+namespace android {
+namespace hardware {
+namespace confirmationui {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::confirmationui::V1_0::generic::Operation;
+using ::android::hardware::keymaster::V4_0::HardwareAuthToken;
+
+uint8_t hmacKey[32];
+
+// Methods from ::android::hardware::confirmationui::V1_0::IConfirmationUI follow.
+Return<ResponseCode> ConfirmationUI::promptUserConfirmation(
+    const sp<IConfirmationResultCallback>& resultCB, const hidl_string& promptText,
+    const hidl_vec<uint8_t>& extraData, const hidl_string& locale,
+    const hidl_vec<UIOption>& uiOptions) {
+    auto& operation = MyOperation::get();
+    return operation.init(resultCB, promptText, extraData, locale, uiOptions);
+}
+
+Return<ResponseCode> ConfirmationUI::deliverSecureInputEvent(
+    const HardwareAuthToken& secureInputToken) {
+    auto& operation = MyOperation::get();
+    return operation.deliverSecureInputEvent(secureInputToken);
+}
+
+Return<void> ConfirmationUI::abort() {
+    auto& operation = MyOperation::get();
+    operation.abort();
+    operation.finalize(hmacKey);
+    return Void();
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace confirmationui
+}  // namespace hardware
+}  // namespace android
diff --git a/confirmationui/1.0/default/ConfirmationUI.h b/confirmationui/1.0/default/ConfirmationUI.h
new file mode 100644
index 0000000..e9e7f99
--- /dev/null
+++ b/confirmationui/1.0/default/ConfirmationUI.h
@@ -0,0 +1,57 @@
+/*
+**
+** Copyright 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.
+*/
+
+#ifndef ANDROID_HARDWARE_CONFIRMATIONUI_V1_0_CONFIRMATIONUI_H
+#define ANDROID_HARDWARE_CONFIRMATIONUI_V1_0_CONFIRMATIONUI_H
+
+#include <android/hardware/confirmationui/1.0/IConfirmationUI.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace confirmationui {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+struct ConfirmationUI : public IConfirmationUI {
+    // Methods from ::android::hardware::confirmationui::V1_0::IConfirmationUI follow.
+    Return<ResponseCode> promptUserConfirmation(const sp<IConfirmationResultCallback>& resultCB,
+                                                const hidl_string& promptText,
+                                                const hidl_vec<uint8_t>& extraData,
+                                                const hidl_string& locale,
+                                                const hidl_vec<UIOption>& uiOptions) override;
+    Return<ResponseCode> deliverSecureInputEvent(
+        const ::android::hardware::keymaster::V4_0::HardwareAuthToken& secureInputToken) override;
+    Return<void> abort() override;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace confirmationui
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_CONFIRMATIONUI_V1_0_CONFIRMATIONUI_H
diff --git a/confirmationui/1.0/default/OWNERS b/confirmationui/1.0/default/OWNERS
new file mode 100644
index 0000000..335660d
--- /dev/null
+++ b/confirmationui/1.0/default/OWNERS
@@ -0,0 +1,2 @@
+jdanis@google.com
+swillden@google.com
diff --git a/confirmationui/1.0/default/PlatformSpecifics.cpp b/confirmationui/1.0/default/PlatformSpecifics.cpp
new file mode 100644
index 0000000..dd039e2
--- /dev/null
+++ b/confirmationui/1.0/default/PlatformSpecifics.cpp
@@ -0,0 +1,62 @@
+/*
+**
+** Copyright 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.
+*/
+
+#include "PlatformSpecifics.h"
+
+#include <openssl/hmac.h>
+#include <openssl/sha.h>
+#include <time.h>
+
+namespace android {
+namespace hardware {
+namespace confirmationui {
+namespace V1_0 {
+namespace implementation {
+
+MonotonicClockTimeStamper::TimeStamp MonotonicClockTimeStamper::now() {
+    timespec ts;
+    if (!clock_gettime(CLOCK_BOOTTIME, &ts)) {
+        return TimeStamp(ts.tv_sec * UINT64_C(1000) + ts.tv_nsec / UINT64_C(1000000));
+    } else {
+        return {};
+    }
+}
+
+support::NullOr<support::array<uint8_t, 32>> HMacImplementation::hmac256(
+    const uint8_t key[32], std::initializer_list<support::ByteBufferProxy> buffers) {
+    HMAC_CTX hmacCtx;
+    HMAC_CTX_init(&hmacCtx);
+    if (!HMAC_Init_ex(&hmacCtx, key, 32, EVP_sha256(), nullptr)) {
+        return {};
+    }
+    for (auto& buffer : buffers) {
+        if (!HMAC_Update(&hmacCtx, buffer.data(), buffer.size())) {
+            return {};
+        }
+    }
+    support::array<uint8_t, 32> result;
+    if (!HMAC_Final(&hmacCtx, result.data(), nullptr)) {
+        return {};
+    }
+    return result;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace confirmationui
+}  // namespace hardware
+}  // namespace android
diff --git a/confirmationui/1.0/default/PlatformSpecifics.h b/confirmationui/1.0/default/PlatformSpecifics.h
new file mode 100644
index 0000000..18b88c8
--- /dev/null
+++ b/confirmationui/1.0/default/PlatformSpecifics.h
@@ -0,0 +1,64 @@
+/*
+**
+** Copyright 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.
+*/
+
+#ifndef CONFIRMATIONUI_1_0_DEFAULT_PLATFORMSPECIFICS_H_
+#define CONFIRMATIONUI_1_0_DEFAULT_PLATFORMSPECIFICS_H_
+
+#include <stdint.h>
+#include <time.h>
+
+#include <android/hardware/confirmationui/1.0/IConfirmationResultCallback.h>
+#include <android/hardware/confirmationui/1.0/generic/GenericOperation.h>
+#include <android/hardware/confirmationui/support/confirmationui_utils.h>
+
+namespace android {
+namespace hardware {
+namespace confirmationui {
+namespace V1_0 {
+namespace implementation {
+
+struct MonotonicClockTimeStamper {
+    class TimeStamp {
+       public:
+        explicit TimeStamp(uint64_t ts) : timestamp_(ts), ok_(true) {}
+        TimeStamp() : timestamp_(0), ok_(false) {}
+        bool isOk() const { return ok_; }
+        operator const uint64_t() const { return timestamp_; }
+
+       private:
+        uint64_t timestamp_;
+        bool ok_;
+    };
+    static TimeStamp now();
+};
+
+class HMacImplementation {
+   public:
+    static support::NullOr<support::array<uint8_t, 32>> hmac256(
+        const uint8_t key[32], std::initializer_list<support::ByteBufferProxy> buffers);
+};
+
+using MyOperation = generic::Operation<sp<IConfirmationResultCallback>, MonotonicClockTimeStamper,
+                                       HMacImplementation>;
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace confirmationui
+}  // namespace hardware
+}  // namespace android
+
+#endif  // CONFIRMATIONUI_1_0_DEFAULT_PLATFORMSPECIFICS_H_
diff --git a/confirmationui/1.0/default/android.hardware.confirmationui@1.0-service.rc b/confirmationui/1.0/default/android.hardware.confirmationui@1.0-service.rc
new file mode 100644
index 0000000..a278028
--- /dev/null
+++ b/confirmationui/1.0/default/android.hardware.confirmationui@1.0-service.rc
@@ -0,0 +1,4 @@
+service vendor.confirmationui-1-0 /vendor/bin/hw/android.hardware.confirmationui@1.0-service
+    class hal
+    user system
+    group system drmrpc
diff --git a/confirmationui/1.0/default/service.cpp b/confirmationui/1.0/default/service.cpp
new file mode 100644
index 0000000..58ec66a
--- /dev/null
+++ b/confirmationui/1.0/default/service.cpp
@@ -0,0 +1,38 @@
+/*
+**
+** Copyright 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 "android.hardware.confirmationui@1.0-service"
+
+#include <android-base/logging.h>
+#include <hidl/HidlTransportSupport.h>
+
+#include "ConfirmationUI.h"
+
+using android::hardware::joinRpcThreadpool;
+
+using android::hardware::confirmationui::V1_0::implementation::ConfirmationUI;
+
+int main() {
+    auto confirmationui = new ConfirmationUI();
+    auto status = confirmationui->registerAsService();
+    if (status != android::OK) {
+        LOG(FATAL) << "Could not register service for ConfirmationIU 1.0 (" << status << ")";
+    }
+
+    joinRpcThreadpool();
+    return -1;  // Should never get here.
+}
diff --git a/confirmationui/1.0/types.hal b/confirmationui/1.0/types.hal
new file mode 100644
index 0000000..fd7ae6a
--- /dev/null
+++ b/confirmationui/1.0/types.hal
@@ -0,0 +1,104 @@
+/*
+ * 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.
+ */
+
+package android.hardware.confirmationui@1.0;
+
+/**
+ * UI modification options.
+ */
+enum UIOption : uint32_t {
+    /** Accessibility: Requests color inverted style. */
+    AccessibilityInverted = 0,
+    /** Accessibility: Requests magnified style. */
+    AccessibilityMagnified = 1,
+};
+
+/**
+ * Codes returned by ConfirmationUI API calls.
+ */
+enum ResponseCode : uint32_t {
+    /** API call succeeded or the user gave approval (result callback). */
+    OK = 0,
+    /** The user canceled the TUI (result callback). */
+    Canceled = 1,
+    /** IConfirmationUI::abort() was called. (result callback). */
+    Aborted = 2,
+    /** Cannot start another prompt. */
+    OperationPending = 3,
+    /** IConfirmationUI::deliverSecureInputEvent call was ingored. */
+    Ignored = 4,
+    /** An unexpected system error occured. */
+    SystemError = 5,
+    /** Returned by an unimplemented API call. */
+    Unimplemented = 6,
+     /**
+       * This is returned when an error is diagnosed that should have been
+       * caught by earlier input sanitization. Should never be seen in production.
+       */
+    Unexpected = 7,
+    /** General UI error. */
+    UIError = 0x10000,
+    UIErrorMissingGlyph,
+    /**
+     * The implementation must return this error code on promptUserConfirmation if the
+     * resulting formatted message does not fit into MessageSize::MAX bytes. It is
+     * advised that the implementation formats the message upon receiving this API call to
+     * be able to diagnose this syndrome.
+     */
+    UIErrorMessageTooLong,
+    UIErrorMalformedUTF8Encoding,
+};
+
+/**
+ * This defines the maximum message size. This indirectly limits the size of the prompt text
+ * and the extra data that can be passed to the confirmation UI. The prompt text and extra data
+ * must fit in to this size including CBOR header information.
+ */
+enum MessageSize : uint32_t { MAX = 0x1800 };
+
+/**
+ * The test key is 32byte word with all bytes set to TestKeyBits::BYTE.
+ */
+enum TestKeyBits: uint8_t { BYTE = 0xA5 };
+
+/**
+ * Test mode commands.
+ *
+ * IConfirmationUI::deliverSecureInputEvent can be used to test certain code paths.
+ * To that end, the caller passes an auth token that has an HMAC keyed with the test key
+ * (see TestKeyBits in types.hal). Implementations first check the HMAC against test key.
+ * If the test key produces a matching HMAC, the implementation evaluates the challenge field
+ * of the auth token against the values defined in TestModeCommand.
+ * If the command indicates that a confirmation token is to be generated the test key MUST be used
+ * to generate this confirmation token.
+ *
+ * See command code for individual test command descriptions.
+ */
+enum TestModeCommands: uint64_t {
+    /**
+     * Simulates the user pressing the OK button on the UI. If no operation is pending
+     * ResponseCode::Ignored must be returned. A pending operation is finalized successfully
+     * see IConfirmationResultCallback::result, however, the test key (see TestKeyBits) MUST be
+     * used to generate the confirmation token.
+     */
+    OK_EVENT = 0,
+    /**
+     * Simulates the user pressing the CANCEL button on the UI. If no operation is pending
+     * Result::Ignored must be returned. A pending operation is finalized as specified in
+     * IConfirmationResultCallback.hal.
+     */
+    CANCEL_EVENT = 1,
+};
diff --git a/confirmationui/support/Android.bp b/confirmationui/support/Android.bp
new file mode 100644
index 0000000..62156b3
--- /dev/null
+++ b/confirmationui/support/Android.bp
@@ -0,0 +1,51 @@
+//
+// 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.
+//
+
+cc_library {
+    name: "android.hardware.confirmationui-support-lib",
+    vendor_available: true,
+    host_supported: true,
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "src/cbor.cpp",
+        "src/confirmationui_utils.cpp",
+    ],
+    export_include_dirs: [
+        "include",
+    ]
+}
+
+cc_test {
+    name: "android.hardware.confirmationui-support-lib-tests",
+    srcs: [
+        "test/gtest_main.cpp",
+        "test/android_cbor_test.cpp",
+        "test/msg_formatting_test.cpp",
+    ],
+    static_libs: [
+        "libgtest",
+        "android.hardware.confirmationui-support-lib",
+    ],
+    shared_libs: [
+        "android.hardware.confirmationui@1.0",
+        "android.hardware.keymaster@4.0",
+        "libhidlbase",
+    ],
+    clang: true,
+    cflags: [ "-O0" ],
+}
diff --git a/confirmationui/support/OWNERS b/confirmationui/support/OWNERS
new file mode 100644
index 0000000..335660d
--- /dev/null
+++ b/confirmationui/support/OWNERS
@@ -0,0 +1,2 @@
+jdanis@google.com
+swillden@google.com
diff --git a/confirmationui/support/include/android/hardware/confirmationui/1.0/generic/GenericOperation.h b/confirmationui/support/include/android/hardware/confirmationui/1.0/generic/GenericOperation.h
new file mode 100644
index 0000000..a88cd40
--- /dev/null
+++ b/confirmationui/support/include/android/hardware/confirmationui/1.0/generic/GenericOperation.h
@@ -0,0 +1,188 @@
+/*
+**
+** Copyright 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.
+*/
+
+#ifndef CONFIRMATIONUI_1_0_DEFAULT_GENERICOPERATION_H_
+#define CONFIRMATIONUI_1_0_DEFAULT_GENERICOPERATION_H_
+
+#include <android/hardware/confirmationui/1.0/types.h>
+#include <android/hardware/confirmationui/support/cbor.h>
+#include <android/hardware/confirmationui/support/confirmationui_utils.h>
+#include <android/hardware/keymaster/4.0/types.h>
+
+namespace android {
+namespace hardware {
+namespace confirmationui {
+namespace V1_0 {
+namespace generic {
+
+namespace {
+using namespace ::android::hardware::confirmationui::support;
+using ::android::hardware::keymaster::V4_0::HardwareAuthToken;
+using ::android::hardware::keymaster::V4_0::HardwareAuthenticatorType;
+
+inline bool hasOption(UIOption option, const hidl_vec<UIOption>& uiOptions) {
+    for (auto& o : uiOptions) {
+        if (o == option) return true;
+    }
+    return false;
+}
+
+template <typename Callback, typename TimeStamper, typename HmacImplementation>
+class Operation {
+    using HMacer = support::HMac<HmacImplementation>;
+
+   public:
+    Operation() : error_(ResponseCode::Ignored), formattedMessageLength_(0) {}
+
+    ResponseCode init(const Callback& resultCB, const hidl_string& promptText,
+                      const hidl_vec<uint8_t>& extraData, const hidl_string& locale,
+                      const hidl_vec<UIOption>& uiOptions) {
+        (void)locale;
+        (void)uiOptions;
+        resultCB_ = resultCB;
+        if (error_ != ResponseCode::Ignored) return ResponseCode::OperationPending;
+        // TODO make copy of promptText before using it may reside in shared buffer
+        auto state = write(
+            WriteState(formattedMessageBuffer_),
+            map(pair(text("prompt"), text(promptText)), pair(text("extra"), bytes(extraData))));
+        switch (state.error_) {
+            case Error::OK:
+                break;
+            case Error::OUT_OF_DATA:
+                return ResponseCode::UIErrorMessageTooLong;
+            case Error::MALFORMED_UTF8:
+                return ResponseCode::UIErrorMalformedUTF8Encoding;
+            case Error::MALFORMED:
+            default:
+                return ResponseCode::Unexpected;
+        }
+        formattedMessageLength_ = state.data_ - formattedMessageBuffer_;
+        // setup TUI and diagnose more UI errors here.
+        // on success record the start time
+        startTime_ = TimeStamper::now();
+        if (!startTime_.isOk()) {
+            return ResponseCode::SystemError;
+        }
+        error_ = ResponseCode::OK;
+        return ResponseCode::OK;
+    }
+
+    void setHmacKey(const uint8_t (&key)[32]) { hmacKey_ = {key}; }
+
+    void abort() {
+        // tear down TUI here
+        if (isPending()) {
+            resultCB_->result(ResponseCode::Aborted, {}, {});
+            error_ = ResponseCode::Ignored;
+        }
+    }
+
+    void userCancel() {
+        // tear down TUI here
+        if (isPending()) error_ = ResponseCode::Canceled;
+    }
+
+    void finalize(const uint8_t key[32]) {
+        if (error_ == ResponseCode::Ignored) return;
+        resultCB_->result(error_, getMessage(), userConfirm(key));
+        error_ = ResponseCode::Ignored;
+        resultCB_ = {};
+    }
+
+    bool isPending() const { return error_ != ResponseCode::Ignored; }
+
+    static Operation& get() {
+        static Operation operation;
+        return operation;
+    }
+
+    ResponseCode deliverSecureInputEvent(const HardwareAuthToken& secureInputToken) {
+        constexpr uint8_t testKeyByte = static_cast<uint8_t>(TestKeyBits::BYTE);
+        constexpr uint8_t testKey[32] = {testKeyByte, testKeyByte, testKeyByte, testKeyByte,
+                                         testKeyByte, testKeyByte, testKeyByte, testKeyByte,
+                                         testKeyByte, testKeyByte, testKeyByte, testKeyByte,
+                                         testKeyByte, testKeyByte, testKeyByte, testKeyByte};
+
+        auto hmac = HMacer::hmac256(testKey, "\0", bytes_cast(secureInputToken.challenge),
+                                    bytes_cast(secureInputToken.userId),
+                                    bytes_cast(secureInputToken.authenticatorId),
+                                    bytes_cast(hton(secureInputToken.authenticatorType)),
+                                    bytes_cast(hton(secureInputToken.timestamp)));
+        if (!hmac.isOk()) return ResponseCode::Unexpected;
+        if (hmac.value() == secureInputToken.mac) {
+            // okay so this is a test token
+            switch (static_cast<TestModeCommands>(secureInputToken.challenge)) {
+                case TestModeCommands::OK_EVENT: {
+                    if (isPending()) {
+                        finalize(testKey);
+                        return ResponseCode::OK;
+                    } else {
+                        return ResponseCode::Ignored;
+                    }
+                }
+                case TestModeCommands::CANCEL_EVENT: {
+                    bool ignored = !isPending();
+                    userCancel();
+                    finalize(testKey);
+                    return ignored ? ResponseCode::Ignored : ResponseCode::OK;
+                }
+                default:
+                    return ResponseCode::Ignored;
+            }
+        }
+        return ResponseCode::Ignored;
+    }
+
+   private:
+    bool acceptAuthToken(const HardwareAuthToken&) { return false; }
+    hidl_vec<uint8_t> getMessage() {
+        hidl_vec<uint8_t> result;
+        if (error_ != ResponseCode::OK) return {};
+        result.setToExternal(formattedMessageBuffer_, formattedMessageLength_);
+        return result;
+    }
+    hidl_vec<uint8_t> userConfirm(const uint8_t key[32]) {
+        // tear down TUI here
+        if (error_ != ResponseCode::OK) return {};
+        confirmationTokenScratchpad_ = HMacer::hmac256(key, "confirmation token", getMessage());
+        if (!confirmationTokenScratchpad_.isOk()) {
+            error_ = ResponseCode::Unexpected;
+            return {};
+        }
+        hidl_vec<uint8_t> result;
+        result.setToExternal(confirmationTokenScratchpad_->data(),
+                             confirmationTokenScratchpad_->size());
+        return result;
+    }
+
+    ResponseCode error_;
+    uint8_t formattedMessageBuffer_[uint32_t(MessageSize::MAX)];
+    size_t formattedMessageLength_;
+    NullOr<array<uint8_t, 32>> confirmationTokenScratchpad_;
+    Callback resultCB_;
+    typename TimeStamper::TimeStamp startTime_;
+    NullOr<array<uint8_t, 32>> hmacKey_;
+};
+
+}  // namespace
+}  // namespace generic
+}  // namespace V1_0
+}  // namespace confirmationui
+}  // namespace hardware
+}  // namespace android
+
+#endif  // CONFIRMATIONUI_1_0_DEFAULT_GENERICOPERATION_H_
diff --git a/confirmationui/support/include/android/hardware/confirmationui/support/cbor.h b/confirmationui/support/include/android/hardware/confirmationui/support/cbor.h
new file mode 100644
index 0000000..f5814d4
--- /dev/null
+++ b/confirmationui/support/include/android/hardware/confirmationui/support/cbor.h
@@ -0,0 +1,335 @@
+/*
+**
+** Copyright 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.
+*/
+
+#ifndef CONFIRMATIONUI_1_0_DEFAULT_CBOR_H_
+#define CONFIRMATIONUI_1_0_DEFAULT_CBOR_H_
+
+#include <stddef.h>
+#include <stdint.h>
+#include <type_traits>
+
+namespace android {
+namespace hardware {
+namespace confirmationui {
+namespace support {
+
+template <typename In, typename Out>
+Out copy(In begin, In end, Out out) {
+    while (begin != end) {
+        *out++ = *begin++;
+    }
+    return out;
+}
+
+enum class Type : uint8_t {
+    NUMBER = 0,
+    NEGATIVE = 1,
+    BYTE_STRING = 2,
+    TEXT_STRING = 3,
+    ARRAY = 4,
+    MAP = 5,
+    TAG = 6,
+    FLOAT = 7,
+};
+
+enum class Error : uint32_t {
+    OK = 0,
+    OUT_OF_DATA = 1,
+    MALFORMED = 2,
+    MALFORMED_UTF8 = 3,
+};
+
+template <typename Key, typename Value>
+struct MapElement {
+    const Key& key_;
+    const Value& value_;
+    MapElement(const Key& key, const Value& value) : key_(key), value_(value) {}
+};
+
+template <typename... Elems>
+struct Array;
+
+template <typename Head, typename... Tail>
+struct Array<Head, Tail...> {
+    const Head& head_;
+    Array<Tail...> tail_;
+    Array(const Head& head, const Tail&... tail) : head_(head), tail_(tail...) {}
+    constexpr size_t size() const { return sizeof...(Tail) + 1; };
+};
+
+template <>
+struct Array<> {};
+
+struct TextStr {};
+struct ByteStr {};
+
+template <typename T, typename Variant>
+struct StringBuffer {
+    const T* data_;
+    size_t size_;
+    StringBuffer(const T* data, size_t size) : data_(data), size_(size) {
+        static_assert(sizeof(T) == 1, "elements too large");
+    }
+    const T* data() const { return data_; }
+    size_t size() const { return size_; }
+};
+
+/**
+ * Takes a char array turns it into a StringBuffer of TextStr type. The length of the resulting
+ * StringBuffer is size - 1, effectively stripping the 0 character from the region being considered.
+ * If the terminating 0 shall not be stripped use text_keep_last.
+ */
+template <size_t size>
+StringBuffer<char, TextStr> text(const char (&str)[size]) {
+    if (size > 0) return StringBuffer<char, TextStr>(str, size - 1);
+    return StringBuffer<char, TextStr>(str, size);
+}
+
+/**
+ * As opposed to text(const char (&str)[size] this function does not strips the last character.
+ */
+template <size_t size>
+StringBuffer<char, TextStr> text_keep_last(const char (&str)[size]) {
+    return StringBuffer<char, TextStr>(str, size);
+}
+
+template <typename T>
+auto getData(const T& v) -> decltype(v.data()) {
+    return v.data();
+}
+
+template <typename T>
+auto getData(const T& v) -> decltype(v.c_str()) {
+    return v.c_str();
+}
+
+template <typename T>
+auto text(const T& str) -> StringBuffer<std::decay_t<decltype(*getData(str))>, TextStr> {
+    return StringBuffer<std::decay_t<decltype(*getData(str))>, TextStr>(getData(str), str.size());
+}
+
+inline StringBuffer<char, TextStr> text(const char* str, size_t size) {
+    return StringBuffer<char, TextStr>(str, size);
+}
+
+template <typename T, size_t size>
+StringBuffer<T, ByteStr> bytes(const T (&str)[size]) {
+    return StringBuffer<T, ByteStr>(str, size);
+}
+
+template <typename T>
+StringBuffer<T, ByteStr> bytes(const T* str, size_t size) {
+    return StringBuffer<T, ByteStr>(str, size);
+}
+
+template <typename T>
+auto bytes(const T& str) -> StringBuffer<std::decay_t<decltype(*getData(str))>, ByteStr> {
+    return StringBuffer<std::decay_t<decltype(*getData(str))>, ByteStr>(getData(str), str.size());
+}
+
+template <typename... Elems>
+struct Map;
+
+template <typename HeadKey, typename HeadValue, typename... Tail>
+struct Map<MapElement<HeadKey, HeadValue>, Tail...> {
+    const MapElement<HeadKey, HeadValue>& head_;
+    Map<Tail...> tail_;
+    Map(const MapElement<HeadKey, HeadValue>& head, const Tail&... tail)
+        : head_(head), tail_(tail...) {}
+    constexpr size_t size() const { return sizeof...(Tail) + 1; };
+};
+
+template <>
+struct Map<> {};
+
+template <typename... Keys, typename... Values>
+Map<MapElement<Keys, Values>...> map(const MapElement<Keys, Values>&... elements) {
+    return Map<MapElement<Keys, Values>...>(elements...);
+}
+
+template <typename... Elements>
+Array<Elements...> arr(const Elements&... elements) {
+    return Array<Elements...>(elements...);
+}
+
+template <typename Key, typename Value>
+MapElement<Key, Value> pair(const Key& k, const Value& v) {
+    return MapElement<Key, Value>(k, v);
+}
+
+template <size_t size>
+struct getUnsignedType;
+
+template <>
+struct getUnsignedType<sizeof(uint8_t)> {
+    typedef uint8_t type;
+};
+template <>
+struct getUnsignedType<sizeof(uint16_t)> {
+    typedef uint16_t type;
+};
+template <>
+struct getUnsignedType<sizeof(uint32_t)> {
+    typedef uint32_t type;
+};
+template <>
+struct getUnsignedType<sizeof(uint64_t)> {
+    typedef uint64_t type;
+};
+
+template <size_t size>
+using Unsigned = typename getUnsignedType<size>::type;
+
+class WriteState {
+   public:
+    WriteState() : data_(nullptr), size_(0), error_(Error::OK) {}
+    WriteState(uint8_t* buffer, size_t size) : data_(buffer), size_(size), error_(Error::OK) {}
+    WriteState(uint8_t* buffer, size_t size, Error error)
+        : data_(buffer), size_(size), error_(error) {}
+    template <size_t size>
+    WriteState(uint8_t (&buffer)[size]) : data_(buffer), size_(size), error_(Error::OK) {}
+
+    WriteState& operator++() {
+        if (size_) {
+            ++data_;
+            --size_;
+        } else {
+            error_ = Error::OUT_OF_DATA;
+        }
+        return *this;
+    }
+    WriteState& operator+=(size_t offset) {
+        if (offset > size_) {
+            error_ = Error::OUT_OF_DATA;
+        } else {
+            data_ += offset;
+            size_ -= offset;
+        }
+        return *this;
+    }
+    operator bool() const { return error_ == Error::OK; }
+
+    uint8_t* data_;
+    size_t size_;
+    Error error_;
+};
+
+WriteState writeHeader(WriteState wState, Type type, const uint64_t value);
+bool checkUTF8Copy(const char* begin, const char* const end, uint8_t* out);
+
+template <typename T>
+WriteState writeNumber(WriteState wState, const T& v) {
+    if (!wState) return wState;
+    if (v >= 0) {
+        return writeHeader(wState, Type::NUMBER, v);
+    } else {
+        return writeHeader(wState, Type::NEGATIVE, UINT64_C(-1) - v);
+    }
+}
+
+inline WriteState write(const WriteState& wState, const uint8_t& v) {
+    return writeNumber(wState, v);
+}
+inline WriteState write(const WriteState& wState, const int8_t& v) {
+    return writeNumber(wState, v);
+}
+inline WriteState write(const WriteState& wState, const uint16_t& v) {
+    return writeNumber(wState, v);
+}
+inline WriteState write(const WriteState& wState, const int16_t& v) {
+    return writeNumber(wState, v);
+}
+inline WriteState write(const WriteState& wState, const uint32_t& v) {
+    return writeNumber(wState, v);
+}
+inline WriteState write(const WriteState& wState, const int32_t& v) {
+    return writeNumber(wState, v);
+}
+inline WriteState write(const WriteState& wState, const uint64_t& v) {
+    return writeNumber(wState, v);
+}
+inline WriteState write(const WriteState& wState, const int64_t& v) {
+    return writeNumber(wState, v);
+}
+
+template <typename T>
+WriteState write(WriteState wState, const StringBuffer<T, TextStr>& v) {
+    wState = writeHeader(wState, Type::TEXT_STRING, v.size());
+    uint8_t* buffer = wState.data_;
+    wState += v.size();
+    if (!wState) return wState;
+    if (!checkUTF8Copy(v.data(), v.data() + v.size(), buffer)) {
+        wState.error_ = Error::MALFORMED_UTF8;
+    }
+    return wState;
+}
+
+template <typename T>
+WriteState write(WriteState wState, const StringBuffer<T, ByteStr>& v) {
+    wState = writeHeader(wState, Type::BYTE_STRING, v.size());
+    uint8_t* buffer = wState.data_;
+    wState += v.size();
+    if (!wState) return wState;
+    static_assert(sizeof(*v.data()) == 1, "elements too large");
+    copy(v.data(), v.data() + v.size(), buffer);
+    return wState;
+}
+
+template <template <typename...> class Arr>
+WriteState writeArrayHelper(WriteState wState, const Arr<>&) {
+    return wState;
+}
+
+template <template <typename...> class Arr, typename Head, typename... Tail>
+WriteState writeArrayHelper(WriteState wState, const Arr<Head, Tail...>& arr) {
+    wState = write(wState, arr.head_);
+    return writeArrayHelper(wState, arr.tail_);
+}
+
+template <typename... Elems>
+WriteState write(WriteState wState, const Map<Elems...>& map) {
+    if (!wState) return wState;
+    wState = writeHeader(wState, Type::MAP, map.size());
+    return writeArrayHelper(wState, map);
+}
+
+template <typename... Elems>
+WriteState write(WriteState wState, const Array<Elems...>& arr) {
+    if (!wState) return wState;
+    wState = writeHeader(wState, Type::ARRAY, arr.size());
+    return writeArrayHelper(wState, arr);
+}
+
+template <typename Key, typename Value>
+WriteState write(WriteState wState, const MapElement<Key, Value>& element) {
+    if (!wState) return wState;
+    wState = write(wState, element.key_);
+    return write(wState, element.value_);
+}
+
+template <typename Head, typename... Tail>
+WriteState write(WriteState wState, const Head& head, const Tail&... tail) {
+    wState = write(wState, head);
+    return write(wState, tail...);
+}
+
+}  // namespace support
+}  // namespace confirmationui
+}  // namespace hardware
+}  // namespace android
+
+#endif  // CONFIRMATIONUI_1_0_DEFAULT_CBOR_H_
diff --git a/confirmationui/support/include/android/hardware/confirmationui/support/confirmationui_utils.h b/confirmationui/support/include/android/hardware/confirmationui/support/confirmationui_utils.h
new file mode 100644
index 0000000..d551433
--- /dev/null
+++ b/confirmationui/support/include/android/hardware/confirmationui/support/confirmationui_utils.h
@@ -0,0 +1,213 @@
+/*
+**
+** Copyright 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.
+*/
+
+#ifndef CONFIRMATIONUI_1_0_SUPPORT_INCLUDE_CONFIRMATIONUI_UTILS_H_
+#define CONFIRMATIONUI_1_0_SUPPORT_INCLUDE_CONFIRMATIONUI_UTILS_H_
+
+#include <stddef.h>
+#include <stdint.h>
+#include <algorithm>
+#include <initializer_list>
+#include <type_traits>
+
+namespace android {
+namespace hardware {
+namespace confirmationui {
+namespace support {
+
+/**
+ * This class wraps a (mostly return) value and stores whether or not the wrapped value is valid out
+ * of band. Note that if the wrapped value is a reference it is unsafe to access the value if
+ * !isOk(). If the wrapped type is a pointer or value and !isOk(), it is still safe to access the
+ * wrapped value. In this case the pointer will be NULL though, and the value will be default
+ * constructed.
+ */
+template <typename ValueT>
+class NullOr {
+    template <typename T>
+    struct reference_initializer {
+        static T&& init() { return *static_cast<std::remove_reference_t<T>*>(nullptr); }
+    };
+    template <typename T>
+    struct pointer_initializer {
+        static T init() { return nullptr; }
+    };
+    template <typename T>
+    struct value_initializer {
+        static T init() { return T(); }
+    };
+    template <typename T>
+    using initializer_t =
+        std::conditional_t<std::is_lvalue_reference<T>::value, reference_initializer<T>,
+                           std::conditional_t<std::is_pointer<T>::value, pointer_initializer<T>,
+                                              value_initializer<T>>>;
+
+   public:
+    NullOr() : value_(initializer_t<ValueT>::init()), null_(true) {}
+    NullOr(ValueT&& value) : value_(std::forward<ValueT>(value)), null_(false) {}
+
+    bool isOk() const { return !null_; }
+
+    const ValueT& value() const & { return value_; }
+    ValueT& value() & { return value_; }
+    ValueT&& value() && { return std::move(value_); }
+
+    const std::remove_reference_t<ValueT>* operator->() const { return &value_; }
+    std::remove_reference_t<ValueT>* operator->() { return &value_; }
+
+   private:
+    ValueT value_;
+    bool null_;
+};
+
+template <typename T, size_t elements>
+class array {
+    using array_type = T[elements];
+
+   public:
+    array() : data_{} {}
+    array(const T (&data)[elements]) { std::copy(data, data + elements, data_); }
+
+    T* data() { return data_; }
+    const T* data() const { return data_; }
+    constexpr size_t size() const { return elements; }
+    operator const array_type&() const { return data_; }
+
+    T* begin() { return data_; }
+    T* end() { return data_ + elements; }
+    const T* begin() const { return data_; }
+    const T* end() const { return data_ + elements; }
+
+   private:
+    array_type data_;
+};
+
+template <typename T>
+auto bytes_cast(const T& v) -> const uint8_t (&)[sizeof(T)] {
+    return *reinterpret_cast<const uint8_t(*)[sizeof(T)]>(&v);
+}
+template <typename T>
+auto bytes_cast(T& v) -> uint8_t (&)[sizeof(T)] {
+    return *reinterpret_cast<uint8_t(*)[sizeof(T)]>(&v);
+}
+
+class ByteBufferProxy {
+    template <typename T>
+    struct has_data {
+        template <typename U>
+        static int f(const U*, const void*) {
+            return 0;
+        }
+        template <typename U>
+        static int* f(const U* u, decltype(u->data())) {
+            return nullptr;
+        }
+        static constexpr bool value = std::is_pointer<decltype(f((T*)nullptr, ""))>::value;
+    };
+
+   public:
+    template <typename T>
+    ByteBufferProxy(const T& buffer, decltype(buffer.data()) = nullptr)
+        : data_(reinterpret_cast<const uint8_t*>(buffer.data())), size_(buffer.size()) {
+        static_assert(sizeof(decltype(*buffer.data())) == 1, "elements to large");
+    }
+
+    // this overload kicks in for types that have .c_str() but not .data(), such as hidl_string.
+    // std::string has both so we need to explicitly disable this overload if .data() is present.
+    template <typename T>
+    ByteBufferProxy(const T& buffer,
+                    std::enable_if_t<!has_data<T>::value, decltype(buffer.c_str())> = nullptr)
+        : data_(reinterpret_cast<const uint8_t*>(buffer.c_str())), size_(buffer.size()) {
+        static_assert(sizeof(decltype(*buffer.c_str())) == 1, "elements to large");
+    }
+
+    template <size_t size>
+    ByteBufferProxy(const char (&buffer)[size])
+        : data_(reinterpret_cast<const uint8_t*>(buffer)), size_(size - 1) {
+        static_assert(size > 0, "even an empty string must be 0-terminated");
+    }
+
+    template <size_t size>
+    ByteBufferProxy(const uint8_t (&buffer)[size]) : data_(buffer), size_(size) {}
+
+    ByteBufferProxy() : data_(nullptr), size_(0) {}
+
+    const uint8_t* data() const { return data_; }
+    size_t size() const { return size_; }
+
+    const uint8_t* begin() const { return data_; }
+    const uint8_t* end() const { return data_ + size_; }
+
+   private:
+    const uint8_t* data_;
+    size_t size_;
+};
+
+/**
+ * Implementer are expected to provide an implementation with the following prototype:
+ *  static NullOr<array<uint8_t, 32>> hmac256(const uint8_t key[32],
+ *                                     std::initializer_list<ByteBufferProxy> buffers);
+ */
+template <typename Impl>
+class HMac {
+   public:
+    template <typename... Data>
+    static NullOr<array<uint8_t, 32>> hmac256(const uint8_t key[32], const Data&... data) {
+        return Impl::hmac256(key, {data...});
+    }
+};
+
+bool operator==(const ByteBufferProxy& lhs, const ByteBufferProxy& rhs);
+
+template <typename IntType, uint32_t byteOrder>
+struct choose_hton;
+
+template <typename IntType>
+struct choose_hton<IntType, __ORDER_LITTLE_ENDIAN__> {
+    inline static IntType hton(const IntType& value) {
+        IntType result = {};
+        const unsigned char* inbytes = reinterpret_cast<const unsigned char*>(&value);
+        unsigned char* outbytes = reinterpret_cast<unsigned char*>(&result);
+        for (int i = sizeof(IntType) - 1; i >= 0; --i) {
+            *(outbytes++) = inbytes[i];
+        }
+        return result;
+    }
+};
+
+template <typename IntType>
+struct choose_hton<IntType, __ORDER_BIG_ENDIAN__> {
+    inline static IntType hton(const IntType& value) { return value; }
+};
+
+template <typename IntType>
+inline IntType hton(const IntType& value) {
+    return choose_hton<IntType, __BYTE_ORDER__>::hton(value);
+}
+
+template <typename IntType>
+inline IntType ntoh(const IntType& value) {
+    // same operation as hton
+    return choose_hton<IntType, __BYTE_ORDER__>::hton(value);
+}
+
+}  // namespace support
+}  // namespace confirmationui
+}  // namespace hardware
+}  // namespace android
+
+#endif  // CONFIRMATIONUI_1_0_SUPPORT_INCLUDE_CONFIRMATIONUI_UTILS_H_
diff --git a/confirmationui/support/include/android/hardware/confirmationui/support/msg_formatting.h b/confirmationui/support/include/android/hardware/confirmationui/support/msg_formatting.h
new file mode 100644
index 0000000..0d03591
--- /dev/null
+++ b/confirmationui/support/include/android/hardware/confirmationui/support/msg_formatting.h
@@ -0,0 +1,471 @@
+/*
+**
+** Copyright 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.
+*/
+
+#ifndef CONFIRMATIONUI_SUPPORT_INCLUDE_ANDROID_HARDWARE_CONFIRMATIONUI_SUPPORT_MSG_FORMATTING_H_
+#define CONFIRMATIONUI_SUPPORT_INCLUDE_ANDROID_HARDWARE_CONFIRMATIONUI_SUPPORT_MSG_FORMATTING_H_
+
+#include <android/hardware/confirmationui/1.0/types.h>
+#include <android/hardware/keymaster/4.0/types.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <algorithm>
+#include <tuple>
+#include <type_traits>
+
+#include <android/hardware/confirmationui/support/confirmationui_utils.h>
+
+namespace android {
+namespace hardware {
+namespace confirmationui {
+namespace support {
+
+template <size_t... I>
+class IntegerSequence {};
+
+namespace integer_sequence {
+
+template <typename Lhs, typename Rhs>
+struct conc {};
+
+template <size_t... ILhs, size_t... IRhs>
+struct conc<IntegerSequence<ILhs...>, IntegerSequence<IRhs...>> {
+    using type = IntegerSequence<ILhs..., IRhs...>;
+};
+
+template <typename Lhs, typename Rhs>
+using conc_t = typename conc<Lhs, Rhs>::type;
+
+template <size_t... n>
+struct make {};
+
+template <size_t n>
+struct make<n> {
+    using type = conc_t<typename make<n - 1>::type, IntegerSequence<n - 1>>;
+};
+template <size_t start, size_t n>
+struct make<start, n> {
+    using type = conc_t<typename make<start, n - 1>::type, IntegerSequence<start + n - 1>>;
+};
+
+template <size_t start>
+struct make<start, start> {
+    using type = IntegerSequence<start>;
+};
+
+template <>
+struct make<0> {
+    using type = IntegerSequence<>;
+};
+
+template <size_t... n>
+using make_t = typename make<n...>::type;
+
+}  // namespace integer_sequence
+
+template <size_t... idx, typename... T>
+std::tuple<std::remove_reference_t<T>&&...> tuple_move_helper(IntegerSequence<idx...>,
+                                                              std::tuple<T...>&& t) {
+    return {std::move(std::get<idx>(t))...};
+}
+
+template <typename... T>
+std::tuple<std::remove_reference_t<T>&&...> tuple_move(std::tuple<T...>&& t) {
+    return tuple_move_helper(integer_sequence::make_t<sizeof...(T)>(), std::move(t));
+}
+
+template <typename... T>
+std::tuple<std::remove_reference_t<T>&&...> tuple_move(std::tuple<T...>& t) {
+    return tuple_move_helper(integer_sequence::make_t<sizeof...(T)>(), std::move(t));
+}
+
+using ::android::hardware::confirmationui::V1_0::ResponseCode;
+using ::android::hardware::confirmationui::V1_0::UIOption;
+using ::android::hardware::keymaster::V4_0::HardwareAuthToken;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+
+template <typename... fields>
+class Message {};
+
+enum class Command : uint32_t {
+    PromptUserConfirmation,
+    DeliverSecureInputEvent,
+    Abort,
+};
+
+template <Command cmd>
+struct Cmd {};
+
+#define DECLARE_COMMAND(cmd) using cmd##_t = Cmd<Command::cmd>
+
+DECLARE_COMMAND(PromptUserConfirmation);
+DECLARE_COMMAND(DeliverSecureInputEvent);
+DECLARE_COMMAND(Abort);
+
+using PromptUserConfirmationMsg = Message<PromptUserConfirmation_t, hidl_string, hidl_vec<uint8_t>,
+                                          hidl_string, hidl_vec<UIOption>>;
+using PromptUserConfirmationResponse = Message<ResponseCode>;
+using DeliverSecureInputEventMsg = Message<DeliverSecureInputEvent_t, HardwareAuthToken>;
+using DeliverSecureInputEventRespose = Message<ResponseCode>;
+using AbortMsg = Message<Abort_t>;
+using ResultMsg = Message<ResponseCode, hidl_vec<uint8_t>, hidl_vec<uint8_t>>;
+
+template <typename T>
+struct StreamState {
+    using ptr_t = volatile T*;
+    volatile T* pos_;
+    size_t bytes_left_;
+    bool good_;
+    template <size_t size>
+    StreamState(T (&buffer)[size]) : pos_(buffer), bytes_left_(size), good_(size > 0) {}
+    StreamState(T* buffer, size_t size) : pos_(buffer), bytes_left_(size), good_(size > 0) {}
+    StreamState() : pos_(nullptr), bytes_left_(0), good_(false) {}
+    StreamState& operator++() {
+        if (good_ && bytes_left_) {
+            ++pos_;
+            --bytes_left_;
+        } else {
+            good_ = false;
+        }
+        return *this;
+    }
+    StreamState& operator+=(size_t offset) {
+        if (!good_ || offset > bytes_left_) {
+            good_ = false;
+        } else {
+            pos_ += offset;
+            bytes_left_ -= offset;
+        }
+        return *this;
+    }
+    operator bool() const { return good_; }
+    volatile T* pos() const { return pos_; };
+};
+
+using WriteStream = StreamState<uint8_t>;
+using ReadStream = StreamState<const uint8_t>;
+
+inline void zero(volatile uint8_t* begin, const volatile uint8_t* end) {
+    while (begin != end) {
+        *begin++ = 0xaa;
+    }
+}
+inline void zero(const volatile uint8_t*, const volatile uint8_t*) {}
+// This odd alignment function aligns the stream position to a 4byte and never 8byte boundary
+// It is to accommodate the 4 byte size field which is then followed by 8byte alligned data.
+template <typename T>
+StreamState<T> unalign(StreamState<T> s) {
+    uint8_t unalignment = uintptr_t(s.pos_) & 0x3;
+    auto pos = s.pos_;
+    if (unalignment) {
+        s += 4 - unalignment;
+    }
+    // now s.pos_ is aligned on a 4byte boundary
+    if ((uintptr_t(s.pos_) & 0x4) == 0) {
+        // if we are 8byte aligned add 4
+        s += 4;
+    }
+    // zero out the gaps when writing
+    zero(pos, s.pos_);
+    return s;
+}
+
+inline WriteStream write(WriteStream out, const uint8_t* buffer, size_t size) {
+    auto pos = out.pos();
+    uint32_t v = size;
+    out += 4 + size;
+    if (out) {
+        if (size != v) {
+            out.good_ = false;
+            return out;
+        }
+        auto& s = bytes_cast(v);
+        pos = std::copy(s, s + 4, pos);
+        std::copy(buffer, buffer + size, pos);
+    }
+    return out;
+}
+template <size_t size>
+WriteStream write(WriteStream out, const uint8_t (&v)[size]) {
+    return write(out, v, size);
+}
+
+inline std::tuple<ReadStream, ReadStream::ptr_t, size_t> read(ReadStream in) {
+    auto pos = in.pos();
+    in += 4;
+    if (!in) return {in, nullptr, 0};
+    uint32_t size;
+    std::copy(pos, pos + 4, bytes_cast(size));
+    pos = in.pos();
+    in += size;
+    if (!in) return {in, nullptr, 0};
+    return {in, pos, size};
+}
+
+template <typename T>
+std::tuple<ReadStream, T> readSimpleType(ReadStream in) {
+    T result;
+    ReadStream::ptr_t pos = nullptr;
+    size_t read_size = 0;
+    std::tie(in, pos, read_size) = read(in);
+    if (!in || read_size != sizeof(T)) {
+        in.good_ = false;
+        return {in, {}};
+    }
+    std::copy(pos, pos + sizeof(T), bytes_cast(result));
+    return {in, std::move(result)};
+}
+
+template <typename T>
+std::tuple<ReadStream, hidl_vec<T>> readSimpleHidlVecInPlace(ReadStream in) {
+    std::tuple<ReadStream, hidl_vec<T>> result;
+    ReadStream::ptr_t pos = nullptr;
+    size_t read_size = 0;
+    std::tie(std::get<0>(result), pos, read_size) = read(in);
+    if (!std::get<0>(result) || read_size % sizeof(T)) {
+        std::get<0>(result).good_ = false;
+        return result;
+    }
+    std::get<1>(result).setToExternal(reinterpret_cast<T*>(const_cast<uint8_t*>(pos)),
+                                      read_size / sizeof(T));
+    return result;
+}
+
+template <typename T>
+WriteStream writeSimpleHidlVec(WriteStream out, const hidl_vec<T>& vec) {
+    return write(out, reinterpret_cast<const uint8_t*>(vec.data()), vec.size() * sizeof(T));
+}
+
+// HardwareAuthToken
+constexpr size_t hatSizeNoMac() {
+    HardwareAuthToken* hat = nullptr;
+    return sizeof hat->challenge + sizeof hat->userId + sizeof hat->authenticatorId +
+           sizeof hat->authenticatorType + sizeof hat->timestamp;
+}
+
+template <typename T>
+inline volatile const uint8_t* copyField(T& field, volatile const uint8_t*(&pos)) {
+    auto& s = bytes_cast(field);
+    std::copy(pos, pos + sizeof(T), s);
+    return pos + sizeof(T);
+}
+inline std::tuple<ReadStream, HardwareAuthToken> read(Message<HardwareAuthToken>, ReadStream in_) {
+    std::tuple<ReadStream, HardwareAuthToken> result;
+    ReadStream& in = std::get<0>(result) = in_;
+    auto& hat = std::get<1>(result);
+    constexpr size_t hatSize = hatSizeNoMac();
+    ReadStream::ptr_t pos = nullptr;
+    size_t read_size = 0;
+    std::tie(in, pos, read_size) = read(in);
+    if (!in || read_size != hatSize) {
+        in.good_ = false;
+        return result;
+    }
+    pos = copyField(hat.challenge, pos);
+    pos = copyField(hat.userId, pos);
+    pos = copyField(hat.authenticatorId, pos);
+    pos = copyField(hat.authenticatorType, pos);
+    pos = copyField(hat.timestamp, pos);
+    std::tie(in, hat.mac) = readSimpleHidlVecInPlace<uint8_t>(in);
+    return result;
+}
+
+template <typename T>
+inline volatile uint8_t* copyField(const T& field, volatile uint8_t*(&pos)) {
+    auto& s = bytes_cast(field);
+    return std::copy(s, &s[sizeof(T)], pos);
+}
+
+inline WriteStream write(WriteStream out, const HardwareAuthToken& v) {
+    auto pos = out.pos();
+    uint32_t size_field = hatSizeNoMac();
+    out += 4 + size_field;
+    if (!out) return out;
+    pos = copyField(size_field, pos);
+    pos = copyField(v.challenge, pos);
+    pos = copyField(v.userId, pos);
+    pos = copyField(v.authenticatorId, pos);
+    pos = copyField(v.authenticatorType, pos);
+    pos = copyField(v.timestamp, pos);
+    return writeSimpleHidlVec(out, v.mac);
+}
+
+// ResponseCode
+inline std::tuple<ReadStream, ResponseCode> read(Message<ResponseCode>, ReadStream in) {
+    return readSimpleType<ResponseCode>(in);
+}
+inline WriteStream write(WriteStream out, const ResponseCode& v) {
+    return write(out, bytes_cast(v));
+}
+
+// hidl_vec<uint8_t>
+inline std::tuple<ReadStream, hidl_vec<uint8_t>> read(Message<hidl_vec<uint8_t>>, ReadStream in) {
+    return readSimpleHidlVecInPlace<uint8_t>(in);
+}
+inline WriteStream write(WriteStream out, const hidl_vec<uint8_t>& v) {
+    return writeSimpleHidlVec(out, v);
+}
+
+// hidl_vec<UIOption>
+inline std::tuple<ReadStream, hidl_vec<UIOption>> read(Message<hidl_vec<UIOption>>, ReadStream in) {
+    in = unalign(in);
+    return readSimpleHidlVecInPlace<UIOption>(in);
+}
+inline WriteStream write(WriteStream out, const hidl_vec<UIOption>& v) {
+    out = unalign(out);
+    return writeSimpleHidlVec(out, v);
+}
+
+// hidl_string
+inline std::tuple<ReadStream, hidl_string> read(Message<hidl_string>, ReadStream in) {
+    std::tuple<ReadStream, hidl_string> result;
+    ReadStream& in_ = std::get<0>(result);
+    hidl_string& result_ = std::get<1>(result);
+    ReadStream::ptr_t pos = nullptr;
+    size_t read_size = 0;
+    std::tie(in_, pos, read_size) = read(in);
+    auto terminating_zero = in_.pos();
+    ++in_;  // skip the terminating zero. Does nothing if the stream was already bad
+    if (!in_) return result;
+    if (*terminating_zero) {
+        in_.good_ = false;
+        return result;
+    }
+    result_.setToExternal(reinterpret_cast<const char*>(const_cast<const uint8_t*>(pos)),
+                          read_size);
+    return result;
+}
+inline WriteStream write(WriteStream out, const hidl_string& v) {
+    out = write(out, reinterpret_cast<const uint8_t*>(v.c_str()), v.size());
+    auto terminating_zero = out.pos();
+    ++out;
+    if (out) {
+        *terminating_zero = 0;
+    }
+    return out;
+}
+
+inline WriteStream write(WriteStream out, Command cmd) {
+    volatile Command* pos = reinterpret_cast<volatile Command*>(out.pos_);
+    out += sizeof(Command);
+    if (out) {
+        *pos = cmd;
+    }
+    return out;
+}
+template <Command cmd>
+WriteStream write(WriteStream out, Cmd<cmd>) {
+    return write(out, cmd);
+}
+
+inline std::tuple<ReadStream, bool> read(ReadStream in, Command cmd) {
+    volatile const Command* pos = reinterpret_cast<volatile const Command*>(in.pos_);
+    in += sizeof(Command);
+    if (!in) return {in, false};
+    return {in, *pos == cmd};
+}
+
+template <Command cmd>
+std::tuple<ReadStream, bool> read(Message<Cmd<cmd>>, ReadStream in) {
+    return read(in, cmd);
+}
+
+inline WriteStream write(Message<>, WriteStream out) {
+    return out;
+}
+
+template <typename Head, typename... Tail>
+WriteStream write(Message<Head, Tail...>, WriteStream out, const Head& head, const Tail&... tail) {
+    out = write(out, head);
+    return write(Message<Tail...>(), out, tail...);
+}
+
+template <Command cmd, typename... Tail>
+WriteStream write(Message<Cmd<cmd>, Tail...>, WriteStream out, const Tail&... tail) {
+    out = write(out, cmd);
+    return write(Message<Tail...>(), out, tail...);
+}
+
+template <Command cmd, typename HEAD, typename... Tail>
+std::tuple<ReadStream, bool, HEAD, Tail...> read(Message<Cmd<cmd>, HEAD, Tail...>, ReadStream in) {
+    bool command_matches;
+    std::tie(in, command_matches) = read(in, cmd);
+    if (!command_matches) return {in, false, HEAD(), Tail()...};
+
+    return {in, true,
+            [&]() -> HEAD {
+                HEAD result;
+                std::tie(in, result) = read(Message<HEAD>(), in);
+                return result;
+            }(),
+            [&]() -> Tail {
+                Tail result;
+                std::tie(in, result) = read(Message<Tail>(), in);
+                return result;
+            }()...};
+}
+
+template <typename... Msg>
+std::tuple<ReadStream, Msg...> read(Message<Msg...>, ReadStream in) {
+    return {in, [&in]() -> Msg {
+                Msg result;
+                std::tie(in, result) = read(Message<Msg>(), in);
+                return result;
+            }()...};
+}
+
+template <typename T>
+struct msg2tuple {};
+
+template <typename... T>
+struct msg2tuple<Message<T...>> {
+    using type = std::tuple<T...>;
+};
+template <Command cmd, typename... T>
+struct msg2tuple<Message<Cmd<cmd>, T...>> {
+    using type = std::tuple<T...>;
+};
+
+template <typename T>
+using msg2tuple_t = typename msg2tuple<T>::type;
+
+template <size_t... idx, typename HEAD, typename... T>
+std::tuple<T&&...> tuple_tail(IntegerSequence<idx...>, std::tuple<HEAD, T...>&& t) {
+    return {std::move(std::get<idx>(t))...};
+}
+
+template <size_t... idx, typename HEAD, typename... T>
+std::tuple<const T&...> tuple_tail(IntegerSequence<idx...>, const std::tuple<HEAD, T...>& t) {
+    return {std::get<idx>(t)...};
+}
+
+template <typename HEAD, typename... Tail>
+std::tuple<Tail&&...> tuple_tail(std::tuple<HEAD, Tail...>&& t) {
+    return tuple_tail(integer_sequence::make_t<1, sizeof...(Tail)>(), std::move(t));
+}
+
+template <typename HEAD, typename... Tail>
+std::tuple<const Tail&...> tuple_tail(const std::tuple<HEAD, Tail...>& t) {
+    return tuple_tail(integer_sequence::make_t<1, sizeof...(Tail)>(), t);
+}
+
+}  // namespace support
+}  // namespace confirmationui
+}  // namespace hardware
+}  // namespace android
+
+#endif  // CONFIRMATIONUI_SUPPORT_INCLUDE_ANDROID_HARDWARE_CONFIRMATIONUI_SUPPORT_MSG_FORMATTING_H_
diff --git a/confirmationui/support/src/cbor.cpp b/confirmationui/support/src/cbor.cpp
new file mode 100644
index 0000000..e7ea164
--- /dev/null
+++ b/confirmationui/support/src/cbor.cpp
@@ -0,0 +1,111 @@
+/*
+**
+** Copyright 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.
+*/
+
+#include <android/hardware/confirmationui/support/cbor.h>
+
+namespace android {
+namespace hardware {
+namespace confirmationui {
+namespace support {
+namespace {
+
+inline uint8_t getByte(const uint64_t& v, const uint8_t index) {
+    return v >> (index * 8);
+}
+
+WriteState writeBytes(WriteState state, uint64_t value, uint8_t size) {
+    auto pos = state.data_;
+    if (!(state += size)) return state;
+    switch (size) {
+        case 8:
+            *pos++ = getByte(value, 7);
+            *pos++ = getByte(value, 6);
+            *pos++ = getByte(value, 5);
+            *pos++ = getByte(value, 4);
+        case 4:
+            *pos++ = getByte(value, 3);
+            *pos++ = getByte(value, 2);
+        case 2:
+            *pos++ = getByte(value, 1);
+        case 1:
+            *pos++ = value;
+            break;
+        default:
+            state.error_ = Error::MALFORMED;
+    }
+    return state;
+}
+
+}  // anonymous namespace
+
+WriteState writeHeader(WriteState wState, Type type, const uint64_t value) {
+    if (!wState) return wState;
+    uint8_t& header = *wState.data_;
+    if (!++wState) return wState;
+    header = static_cast<uint8_t>(type) << 5;
+    if (value < 24) {
+        header |= static_cast<uint8_t>(value);
+    } else if (value < 0x100) {
+        header |= 24;
+        wState = writeBytes(wState, value, 1);
+    } else if (value < 0x10000) {
+        header |= 25;
+        wState = writeBytes(wState, value, 2);
+    } else if (value < 0x100000000) {
+        header |= 26;
+        wState = writeBytes(wState, value, 4);
+    } else {
+        header |= 27;
+        wState = writeBytes(wState, value, 8);
+    }
+    return wState;
+}
+
+bool checkUTF8Copy(const char* begin, const char* const end, uint8_t* out) {
+    uint32_t multi_byte_length = 0;
+    while (begin != end) {
+        if (multi_byte_length) {
+            // parsing multi byte character - must start with 10xxxxxx
+            --multi_byte_length;
+            if ((*begin & 0xc0) != 0x80) return false;
+        } else if (!((*begin) & 0x80)) {
+            // 7bit character -> nothing to be done
+        } else {
+            // msb is set and we were not parsing a multi byte character
+            // so this must be a header byte
+            char c = *begin << 1;
+            while (c & 0x80) {
+                ++multi_byte_length;
+                c <<= 1;
+            }
+            // headers of the form 10xxxxxx are not allowed
+            if (multi_byte_length < 1) return false;
+            // chars longer than 4 bytes are not allowed (multi_byte_length does not count the
+            // header thus > 3
+            if (multi_byte_length > 3) return false;
+        }
+        if (out) *out++ = *reinterpret_cast<const uint8_t*>(begin++);
+    }
+    // if the string ends in the middle of a multi byte char it is invalid
+    if (multi_byte_length) return false;
+    return true;
+}
+
+}  // namespace support
+}  // namespace confirmationui
+}  // namespace hardware
+}  // namespace android
diff --git a/confirmationui/support/src/confirmationui_utils.cpp b/confirmationui/support/src/confirmationui_utils.cpp
new file mode 100644
index 0000000..708f0d56
--- /dev/null
+++ b/confirmationui/support/src/confirmationui_utils.cpp
@@ -0,0 +1,39 @@
+/*
+**
+** Copyright 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.
+*/
+
+#include <android/hardware/confirmationui/support/confirmationui_utils.h>
+
+namespace android {
+namespace hardware {
+namespace confirmationui {
+namespace support {
+
+bool operator==(const ByteBufferProxy& lhs, const ByteBufferProxy& rhs) {
+    if (lhs.size() == rhs.size()) {
+        auto lhsi = lhs.begin();
+        auto rhsi = rhs.begin();
+        while (lhsi != lhs.end()) {
+            if (*lhsi++ != *rhsi++) return false;
+        }
+    }
+    return true;
+}
+
+}  // namespace support
+}  // namespace confirmationui
+}  // namespace hardware
+}  // namespace android
diff --git a/confirmationui/support/test/android_cbor_test.cpp b/confirmationui/support/test/android_cbor_test.cpp
new file mode 100644
index 0000000..4a5a362
--- /dev/null
+++ b/confirmationui/support/test/android_cbor_test.cpp
@@ -0,0 +1,197 @@
+/*
+**
+** Copyright 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.
+*/
+
+#include <android/hardware/confirmationui/support/cbor.h>
+
+#include <cstddef>
+#include <cstdint>
+#include <iomanip>
+#include <iostream>
+
+#include <gtest/gtest.h>
+
+using namespace android::hardware::confirmationui::support;
+
+uint8_t testVector[] = {
+    0xA4, 0x63, 0x6B, 0x65, 0x79, 0x65, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x63, 0x6B, 0x65, 0x79, 0x4D,
+    0x31, 0x30, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x31, 0x30, 0x00, 0x04, 0x07, 0x1B,
+    0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x07, 0x1A, 0xFD, 0x49, 0x8C, 0xFF,
+    0xFF, 0x82, 0x69, 0xE2, 0x99, 0xA8, 0xE2, 0x9A, 0x96, 0xE2, 0xB6, 0x96, 0x59, 0x01, 0x91, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x00,
+};
+
+// 400 'a's and a '\0'
+constexpr char fourHundredAs[] =
+    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+    "aaaaaaaaaaaaaaaaaaaaaaaa";
+
+WriteState writeTest(WriteState state) {
+    return write(state,                                                     //
+                 map(                                                       //
+                     pair(text("key"), text("value")),                      //
+                     pair(text("key"), bytes("100101010010")),              //
+                     pair(4, 7),                                            //
+                     pair((UINT64_C(1) << 62), INT64_C(-2000000000000000))  //
+                     ),                                                     //
+                 arr(text("♨⚖ⶖ"), bytes(fourHundredAs)));
+}
+
+TEST(Cbor, FeatureTest) {
+    uint8_t buffer[0x1000];
+    WriteState state(buffer);
+    state = writeTest(state);
+    ASSERT_EQ(sizeof(testVector), size_t(state.data_ - buffer));
+    ASSERT_EQ(Error::OK, state.error_);
+    ASSERT_EQ(0, memcmp(buffer, testVector, sizeof(testVector)));
+}
+
+// Test if in all write cases an out of data error is correctly propagated and we don't
+// write beyond  the end of the buffer.
+TEST(Cbor, BufferTooShort) {
+    uint8_t buffer[0x1000];
+    for (size_t s = 1; s < sizeof(testVector); ++s) {
+        memset(buffer, 0x22, 0x1000);  // 0x22 is not in the testVector
+        WriteState state(buffer, s);
+        state = writeTest(state);
+        for (size_t t = s; t < 0x1000; ++t) {
+            ASSERT_EQ(0x22, buffer[t]);  // check if a canary has been killed
+        }
+        ASSERT_EQ(Error::OUT_OF_DATA, state.error_);
+    }
+}
+
+TEST(Cbor, MalformedUTF8Test_Stray) {
+    uint8_t buffer[20];
+    WriteState state(buffer);
+    char malformed[] = {char(0x80), 0};
+    state = write(state, text(malformed));
+    ASSERT_EQ(Error::MALFORMED_UTF8, state.error_);
+}
+
+TEST(Cbor, MalformendUTF8Test_StringEndsMidMultiByte) {
+    uint8_t buffer[20];
+    WriteState state(buffer);
+    char malformed[] = {char(0xc0), 0};
+    state = write(state, text(malformed));
+    ASSERT_EQ(Error::MALFORMED_UTF8, state.error_);
+}
+
+TEST(Cbor, UTF8Test_TwoBytes) {
+    uint8_t buffer[20];
+    WriteState state(buffer);
+    char neat[] = {char(0xc3), char(0x82), 0};
+    state = write(state, text(neat));
+    ASSERT_EQ(Error::OK, state.error_);
+}
+
+TEST(Cbor, UTF8Test_ThreeBytes) {
+    uint8_t buffer[20];
+    WriteState state(buffer);
+    char neat[] = {char(0xe3), char(0x82), char(0x82), 0};
+    state = write(state, text(neat));
+    ASSERT_EQ(Error::OK, state.error_);
+}
+
+TEST(Cbor, UTF8Test_FourBytes) {
+    uint8_t buffer[20];
+    WriteState state(buffer);
+    char neat[] = {char(0xf3), char(0x82), char(0x82), char(0x82), 0};
+    state = write(state, text(neat));
+    ASSERT_EQ(Error::OK, state.error_);
+}
+
+TEST(Cbor, MalformendUTF8Test_CharacterTooLong) {
+    uint8_t buffer[20];
+    WriteState state(buffer);
+    char malformed[] = {char(0xf8), char(0x82), char(0x82), char(0x82), char(0x82), 0};
+    state = write(state, text(malformed));
+    ASSERT_EQ(Error::MALFORMED_UTF8, state.error_);
+}
+
+TEST(Cbor, MalformendUTF8Test_StringEndsMidMultiByte2) {
+    uint8_t buffer[20];
+    WriteState state(buffer);
+    char malformed[] = {char(0xc0), char(0x82), char(0x83), 0};
+    state = write(state, text(malformed));
+    ASSERT_EQ(Error::MALFORMED_UTF8, state.error_);
+}
+
+TEST(Cbor, MinimalViableHeaderSizeTest) {
+    uint8_t buffer[20];
+    WriteState state(buffer);
+    state = writeHeader(state, Type::NUMBER, 23);
+    ASSERT_EQ(state.data_ - buffer, 1);
+
+    state = WriteState(buffer);
+    state = writeHeader(state, Type::NUMBER, 24);
+    ASSERT_EQ(state.data_ - buffer, 2);
+
+    state = WriteState(buffer);
+    state = writeHeader(state, Type::NUMBER, 0xff);
+    ASSERT_EQ(state.data_ - buffer, 2);
+
+    state = WriteState(buffer);
+    state = writeHeader(state, Type::NUMBER, 0x100);
+    ASSERT_EQ(state.data_ - buffer, 3);
+
+    state = WriteState(buffer);
+    state = writeHeader(state, Type::NUMBER, 0xffff);
+    ASSERT_EQ(state.data_ - buffer, 3);
+
+    state = WriteState(buffer);
+    state = writeHeader(state, Type::NUMBER, 0x10000);
+    ASSERT_EQ(state.data_ - buffer, 5);
+
+    state = WriteState(buffer);
+    state = writeHeader(state, Type::NUMBER, 0xffffffff);
+    ASSERT_EQ(state.data_ - buffer, 5);
+
+    state = WriteState(buffer);
+    state = writeHeader(state, Type::NUMBER, 0x100000000);
+    ASSERT_EQ(state.data_ - buffer, 9);
+
+    state = WriteState(buffer);
+    state = writeHeader(state, Type::NUMBER, 0xffffffffffffffff);
+    ASSERT_EQ(state.data_ - buffer, 9);
+}
diff --git a/confirmationui/support/test/gtest_main.cpp b/confirmationui/support/test/gtest_main.cpp
new file mode 100644
index 0000000..43fc5a3
--- /dev/null
+++ b/confirmationui/support/test/gtest_main.cpp
@@ -0,0 +1,23 @@
+/*
+**
+** Copyright 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.
+*/
+
+#include <gtest/gtest.h>
+
+int main(int argc, char* argv[]) {
+    ::testing::InitGoogleTest(&argc, argv);
+    return RUN_ALL_TESTS();
+}
diff --git a/confirmationui/support/test/msg_formatting_test.cpp b/confirmationui/support/test/msg_formatting_test.cpp
new file mode 100644
index 0000000..90ed84c
--- /dev/null
+++ b/confirmationui/support/test/msg_formatting_test.cpp
@@ -0,0 +1,128 @@
+/*
+**
+** Copyright 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.
+*/
+
+#include <stddef.h>
+#include <stdint.h>
+#include <iomanip>
+#include <iostream>
+#include <string>
+
+#include <android/hardware/confirmationui/support/msg_formatting.h>
+#include <gtest/gtest.h>
+
+using android::hardware::confirmationui::support::Message;
+using android::hardware::confirmationui::support::WriteStream;
+using android::hardware::confirmationui::support::ReadStream;
+using android::hardware::confirmationui::support::PromptUserConfirmationMsg;
+using android::hardware::confirmationui::support::write;
+using ::android::hardware::confirmationui::V1_0::UIOption;
+using ::android::hardware::keymaster::V4_0::HardwareAuthToken;
+using ::android::hardware::keymaster::V4_0::HardwareAuthenticatorType;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+
+#ifdef DEBUG_MSG_FORMATTING
+namespace {
+
+char nibble2hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
+                       '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+
+std::ostream& hexdump(std::ostream& out, const uint8_t* data, size_t size) {
+    for (size_t i = 0; i < size; ++i) {
+        uint8_t byte = data[i];
+        out << (nibble2hex[0x0F & (byte >> 4)]);
+        out << (nibble2hex[0x0F & byte]);
+        switch (i & 0xf) {
+            case 0xf:
+                out << "\n";
+                break;
+            case 7:
+                out << "  ";
+                break;
+            default:
+                out << " ";
+                break;
+        }
+    }
+    return out;
+}
+
+}  // namespace
+#endif
+
+TEST(MsgFormattingTest, FeatureTest) {
+    uint8_t buffer[0x1000];
+
+    WriteStream out(buffer);
+    out = unalign(out);
+    out += 4;
+    auto begin = out.pos();
+    out = write(
+        PromptUserConfirmationMsg(), out, hidl_string("Do you?"),
+        hidl_vec<uint8_t>{0x01, 0x02, 0x03}, hidl_string("en"),
+        hidl_vec<UIOption>{UIOption::AccessibilityInverted, UIOption::AccessibilityMagnified});
+
+    ReadStream in(buffer);
+    in = unalign(in);
+    in += 4;
+    hidl_string prompt;
+    hidl_vec<uint8_t> extra;
+    hidl_string locale;
+    hidl_vec<UIOption> uiOpts;
+    bool command_matches;
+    std::tie(in, command_matches, prompt, extra, locale, uiOpts) =
+        read(PromptUserConfirmationMsg(), in);
+    ASSERT_TRUE(in);
+    ASSERT_TRUE(command_matches);
+    ASSERT_EQ(hidl_string("Do you?"), prompt);
+    ASSERT_EQ((hidl_vec<uint8_t>{0x01, 0x02, 0x03}), extra);
+    ASSERT_EQ(hidl_string("en"), locale);
+    ASSERT_EQ(
+        (hidl_vec<UIOption>{UIOption::AccessibilityInverted, UIOption::AccessibilityMagnified}),
+        uiOpts);
+
+#ifdef DEBUG_MSG_FORMATTING
+    hexdump(std::cout, buffer, 100) << std::endl;
+#endif
+
+    // The following assertions check that the hidl_[vec|string] types are in fact read in place,
+    // and no copying occurs. Copying results in heap allocation which we intend to avoid.
+    ASSERT_EQ(8, const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(prompt.c_str())) - begin);
+    ASSERT_EQ(20, extra.data() - begin);
+    ASSERT_EQ(27, const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(locale.c_str())) - begin);
+    ASSERT_EQ(40, reinterpret_cast<uint8_t*>(uiOpts.data()) - begin);
+}
+
+TEST(MsgFormattingTest, HardwareAuthTokenTest) {
+    uint8_t buffer[0x1000];
+
+    HardwareAuthToken expected, actual;
+    expected.authenticatorId = 0xa1a3a4a5a6a7a8;
+    expected.authenticatorType = HardwareAuthenticatorType::NONE;
+    expected.challenge = 0xb1b2b3b4b5b6b7b8;
+    expected.userId = 0x1122334455667788;
+    expected.timestamp = 0xf1f2f3f4f5f6f7f8;
+    expected.mac =
+        hidl_vec<uint8_t>{1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15, 16,
+                          17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32};
+
+    WriteStream out(buffer);
+    out = write(Message<HardwareAuthToken>(), out, expected);
+    ReadStream in(buffer);
+    std::tie(in, actual) = read(Message<HardwareAuthToken>(), in);
+    ASSERT_EQ(expected, actual);
+}
diff --git a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerTestUtils.h b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerTestUtils.h
index 29b9de3..00d9d8c 100644
--- a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerTestUtils.h
+++ b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerTestUtils.h
@@ -58,10 +58,12 @@
   std::string dumpDebugInfo();
   std::unique_ptr<ComposerClient> createClient();
 
+ protected:
+  sp<IComposer> mComposer;
+
  private:
   void init();
 
-  sp<IComposer> mComposer;
   std::unordered_set<IComposer::Capability> mCapabilities;
 };
 
diff --git a/graphics/composer/2.2/Android.bp b/graphics/composer/2.2/Android.bp
new file mode 100644
index 0000000..633a208
--- /dev/null
+++ b/graphics/composer/2.2/Android.bp
@@ -0,0 +1,20 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.graphics.composer@2.2",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "IComposer.hal",
+        "IComposerClient.hal",
+    ],
+    interfaces: [
+        "android.hardware.graphics.common@1.0",
+        "android.hardware.graphics.composer@2.1",
+        "android.hidl.base@1.0",
+    ],
+    gen_java: false,
+}
+
diff --git a/graphics/composer/2.2/IComposer.hal b/graphics/composer/2.2/IComposer.hal
new file mode 100644
index 0000000..05052c8
--- /dev/null
+++ b/graphics/composer/2.2/IComposer.hal
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+package android.hardware.graphics.composer@2.2;
+
+import @2.1::IComposer;
+
+interface IComposer extends @2.1::IComposer {
+
+    /* createClient from @2.1::IComposer must return an instance of @2.2::IComposerClient */
+
+};
diff --git a/graphics/composer/2.2/IComposerClient.hal b/graphics/composer/2.2/IComposerClient.hal
new file mode 100644
index 0000000..dcd9c8d
--- /dev/null
+++ b/graphics/composer/2.2/IComposerClient.hal
@@ -0,0 +1,263 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+package android.hardware.graphics.composer@2.2;
+
+import android.hardware.graphics.common@1.0::PixelFormat;
+import android.hardware.graphics.common@1.0::Dataspace;
+import @2.1::IComposerClient;
+import @2.1::Display;
+import @2.1::Error;
+
+interface IComposerClient extends @2.1::IComposerClient {
+
+    enum PowerMode : @2.1::IComposerClient.PowerMode {
+        /**
+         * The display is configured as in ON but may stop applying display
+         * updates from the client. This is effectively a hint to the device
+         * that drawing to the display has been suspended and that the the
+         * device must remain on and continue displaying its current contents
+         * indefinitely until the power mode changes.
+         *
+         * This mode may also be used as a signal to enable hardware-based
+         * functionality to take over the display and manage it autonomously
+         * to implement a low power always-on display.
+         */
+        ON_SUSPEND = 4
+    };
+
+    /**
+     * Following enums define keys for metadata defined by SMPTE ST 2086:2014
+     * and CTA 861.3.
+     */
+    enum PerFrameMetadataKey : int32_t {
+        /** SMPTE ST 2084:2014.
+         * Coordinates defined in CIE 1931 xy chromaticity space
+         */
+        /** SMPTE ST 2084:2014 */
+        DISPLAY_RED_PRIMARY_X,
+        /** SMPTE ST 2084:2014 */
+        DISPLAY_RED_PRIMARY_Y,
+        /** SMPTE ST 2084:2014 */
+        DISPLAY_GREEN_PRIMARY_X,
+        /** SMPTE ST 2084:2014 */
+        DISPLAY_GREEN_PRIMARY_Y,
+        /** SMPTE ST 2084:2014 */
+        DISPLAY_BLUE_PRIMARY_X,
+        /** SMPTE ST 2084:2014 */
+        DISPLAY_BLUE_PRIMARY_Y,
+        /** SMPTE ST 2084:2014 */
+        WHITE_POINT_X,
+        /** SMPTE ST 2084:2014 */
+        WHITE_POINT_Y,
+        /** SMPTE ST 2084:2014.
+         * Units: nits
+         * max as defined by ST 2048: 10,000 nits
+         */
+        MAX_LUMINANCE,
+        /** SMPTE ST 2084:2014 */
+        MIN_LUMINANCE,
+        /** CTA 861.3 */
+        MAX_CONTENT_LIGHT_LEVEL,
+        /** CTA 861.3 */
+        MAX_FRAME_AVERAGE_LIGHT_LEVEL,
+    };
+
+    struct PerFrameMetadata {
+        PerFrameMetadataKey key;
+        float value;
+    };
+
+    struct FloatColor {
+        float r;
+        float g;
+        float b;
+        float a;
+    };
+
+    enum Command : @2.1::IComposerClient.Command {
+        /**
+         * setPerFrameMetadata(Display display, vec<PerFrameMetadata> data)
+         * Sets the PerFrameMetadata for the display. This metadata must be used
+         * by the implementation to better tone map content to that display.
+         *
+         * This is a method that may be called every frame. Thus it's
+         * implemented using buffered transport.
+         * SET_PER_FRAME_METADATA is the command used by the buffered transport
+         * mechanism.
+         */
+        SET_PER_FRAME_METADATA = 0x207 << @2.1::IComposerClient.Command:OPCODE_SHIFT,
+
+        /**
+         * SET_LAYER_COLOR has this pseudo prototype
+         *
+         *   setLayerColor(FloatColor color);
+         *
+         * Sets the color of the given layer. If the composition type of the layer
+         * is not Composition::SOLID_COLOR, this call must succeed and have no
+         * other effect.
+         *
+         * @param color is the new color using float type.
+         */
+        SET_LAYER_FLOAT_COLOR = 0x40c << @2.1::IComposerClient.Command:OPCODE_SHIFT,
+    };
+
+    /**
+     * Returns the PerFrameMetadataKeys that are supported by this device.
+     *
+     * @param display is the display on which to create the layer.
+     * @return keys is the vector of PerFrameMetadataKey keys that are
+     *        supported by this device.
+     * @return error is NONE upon success. Otherwise,
+     *         UNSUPPORTED if not supported on underlying HAL
+     */
+    getPerFrameMetadataKeys(Display display)
+        generates (Error error,
+                   vec<PerFrameMetadataKey> keys);
+
+    /**
+     * getReadbackBufferAttributes
+     * Returns the format which should be used when allocating a buffer for use by
+     * device readback as well as the dataspace in which its contents should be
+     * interpreted.
+     *
+     * The width and height of this buffer must be those of the currently-active
+     * display configuration, and the usage flags must consist of the following:
+     *   BufferUsage::CPU_READ | BufferUsage::GPU_TEXTURE |
+     *   BufferUsage::COMPOSER_OUTPUT
+     *
+     * The format and dataspace provided must be sufficient such that if a
+     * correctly-configured buffer is passed into setReadbackBuffer, filled by
+     * the device, and then displayed by the client as a full-screen buffer, the
+     * output of the display remains the same (subject to the note about protected
+     * content in the description of setReadbackBuffer).
+     *
+     * Parameters:
+     * @param display - the display on which to create the layer.
+     *
+     * @return format - the format the client should use when allocating a device
+     *       readback buffer
+     * @return dataspace - the dataspace to use when interpreting the
+     *       contents of a device readback buffer
+     * @return error is NONE upon success. Otherwise,
+     *         BAD_DISPLAY when an invalid display handle was passed in.
+     *         UNSUPPORTED if not supported on underlying HAL
+     *
+     * See also:
+     *   setReadbackBuffer
+     *   getReadbackBufferFence
+     */
+    getReadbackBufferAttributes(Display display)
+        generates (Error error,
+                   PixelFormat format,
+                   Dataspace dataspace);
+
+    /**
+     * getReadbackBufferFence
+     * Returns an acquire sync fence file descriptor which must signal when the
+     * buffer provided to setReadbackBuffer has been filled by the device and is
+     * safe for the client to read.
+     *
+     * If it is already safe to read from this buffer, -1 may be returned instead.
+     * The client takes ownership of this file descriptor and is responsible for
+     * closing it when it is no longer needed.
+     *
+     * This function must be called immediately after the composition cycle being
+     * captured into the readback buffer. The complete ordering of a readback buffer
+     * capture is as follows:
+     *
+     *   getReadbackBufferAttributes
+     *   // Readback buffer is allocated
+     *   // Many frames may pass
+     *
+     *   setReadbackBuffer
+     *   validateDisplay
+     *   presentDisplay
+     *   getReadbackBufferFence
+     *   // Implicitly wait on the acquire fence before accessing the buffer
+     *
+     * Parameters:
+     * @param display - the display on which to create the layer.
+     *
+     * @return acquireFence - a sync fence file descriptor as described above; pointer
+     *       must be non-NULL
+     * @return error - is HWC2_ERROR_NONE or one of the following errors:
+     *         BAD_DISPLAY - an invalid display handle was passed in
+     *         UNSUPPORTED if not supported on underlying HAL
+     *
+     * See also:
+     *   getReadbackBufferAttributes
+     *   setReadbackBuffer
+     */
+    getReadbackBufferFence(Display display)
+                generates (Error error,
+                           handle acquireFence);
+
+    /**
+     * setReadbackBuffer
+     * Sets the readback buffer to be filled with the contents of the next
+     * composition performed for this display (i.e., the contents present at the
+     * time of the next validateDisplay/presentDisplay cycle).
+     *
+     * This buffer must have been allocated as described in
+     * getReadbackBufferAttributes and is in the dataspace provided by the same.
+     *
+     * If there is hardware protected content on the display at the time of the next
+     * composition, the area of the readback buffer covered by such content must be
+     * completely black. Any areas of the buffer not covered by such content may
+     * optionally be black as well.
+     *
+     * The release fence file descriptor provided works identically to the one
+     * described for setOutputBuffer.
+     *
+     * This function must not be called between any call to validateDisplay and a
+     * subsequent call to presentDisplay.
+     *
+     * Parameters:
+     * @param display - the display on which to create the layer.
+     * @param buffer - the new readback buffer
+     * @param releaseFence - a sync fence file descriptor as described in setOutputBuffer
+     *
+     * @return error - is HWC2_ERROR_NONE or one of the following errors:
+     *   HWC2_ERROR_BAD_DISPLAY - an invalid display handle was passed in
+     *   HWC2_ERROR_BAD_PARAMETER - the new readback buffer handle was invalid
+     *
+     * See also:
+     *   getReadbackBufferAttributes
+     *   getReadbackBufferFence
+     */
+    setReadbackBuffer(Display display, handle buffer, handle releaseFence) generates (Error error);
+
+    /**
+     * setPowerMode_2_2
+     * Sets the power mode of the given display. The transition must be
+     * complete when this function returns. It is valid to call this function
+     * multiple times with the same power mode.
+     *
+     * All displays must support PowerMode::ON and PowerMode::OFF.  Whether a
+     * display supports PowerMode::DOZE or PowerMode::DOZE_SUSPEND may be
+     * queried using getDozeSupport.
+     *
+     * @param display is the display to which the power mode is set.
+     * @param mode is the new power mode.
+     * @return error is NONE upon success. Otherwise,
+     *         BAD_DISPLAY when an invalid display handle was passed in.
+     *         BAD_PARAMETER when mode was not a valid power mode.
+     *         UNSUPPORTED when mode is not supported on this display.
+     */
+    setPowerMode_2_2(Display display, PowerMode mode) generates (Error error);
+
+};
diff --git a/graphics/composer/2.2/utils/OWNERS b/graphics/composer/2.2/utils/OWNERS
new file mode 100644
index 0000000..1beb074
--- /dev/null
+++ b/graphics/composer/2.2/utils/OWNERS
@@ -0,0 +1,8 @@
+# Graphics team
+courtneygo@google.com
+olv@google.com
+stoza@google.com
+
+# VTS team
+yim@google.com
+zhuoyao@google.com
diff --git a/graphics/composer/2.2/utils/command-buffer/Android.bp b/graphics/composer/2.2/utils/command-buffer/Android.bp
new file mode 100644
index 0000000..efaabd4
--- /dev/null
+++ b/graphics/composer/2.2/utils/command-buffer/Android.bp
@@ -0,0 +1,13 @@
+cc_library_headers {
+    name: "android.hardware.graphics.composer@2.2-command-buffer",
+    defaults: ["hidl_defaults"],
+    vendor_available: true,
+    shared_libs: [
+        "android.hardware.graphics.composer@2.1",
+        "android.hardware.graphics.composer@2.2",
+    ],
+    header_libs: [
+        "android.hardware.graphics.composer@2.1-command-buffer",
+    ],
+    export_include_dirs: ["include"],
+}
diff --git a/graphics/composer/2.2/utils/command-buffer/include/composer-command-buffer/2.2/ComposerCommandBuffer.h b/graphics/composer/2.2/utils/command-buffer/include/composer-command-buffer/2.2/ComposerCommandBuffer.h
new file mode 100644
index 0000000..c803d3c
--- /dev/null
+++ b/graphics/composer/2.2/utils/command-buffer/include/composer-command-buffer/2.2/ComposerCommandBuffer.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#pragma once
+
+#ifndef LOG_TAG
+#warn "ComposerCommandBuffer.h included without LOG_TAG"
+#endif
+
+#undef LOG_NDEBUG
+#define LOG_NDEBUG 0
+
+#include <algorithm>
+#include <limits>
+#include <memory>
+#include <vector>
+
+#include <inttypes.h>
+#include <string.h>
+
+#include <android/hardware/graphics/composer/2.2/IComposer.h>
+#include <android/hardware/graphics/composer/2.2/IComposerClient.h>
+#include <fmq/MessageQueue.h>
+#include <log/log.h>
+#include <sync/sync.h>
+
+#include <composer-command-buffer/2.1/ComposerCommandBuffer.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_2 {
+
+using android::hardware::MessageQueue;
+using android::hardware::graphics::common::V1_0::ColorTransform;
+using android::hardware::graphics::common::V1_0::Dataspace;
+using android::hardware::graphics::common::V1_0::Transform;
+using android::hardware::graphics::composer::V2_1::Config;
+using android::hardware::graphics::composer::V2_1::Display;
+using android::hardware::graphics::composer::V2_1::Error;
+using android::hardware::graphics::composer::V2_1::IComposerCallback;
+using android::hardware::graphics::composer::V2_1::Layer;
+using android::hardware::graphics::composer::V2_2::IComposerClient;
+
+using CommandQueueType = MessageQueue<uint32_t, kSynchronizedReadWrite>;
+
+// This class helps build a command queue.  Note that all sizes/lengths are in
+// units of uint32_t's.
+class CommandWriterBase : public V2_1::CommandWriterBase {
+   public:
+    CommandWriterBase(uint32_t initialMaxSize) : V2_1::CommandWriterBase(initialMaxSize) {}
+
+    static constexpr uint16_t kSetLayerFloatColorLength = 4;
+    void setLayerFloatColor(IComposerClient::FloatColor color) {
+        beginCommand_2_2(IComposerClient::Command::SET_LAYER_FLOAT_COLOR,
+                         kSetLayerFloatColorLength);
+        writeFloatColor(color);
+        endCommand();
+    }
+
+    void setPerFrameMetadata(const hidl_vec<IComposerClient::PerFrameMetadata>& metadataVec) {
+        beginCommand_2_2(IComposerClient::Command::SET_PER_FRAME_METADATA, metadataVec.size() * 2);
+        for (const auto& metadata : metadataVec) {
+            writeSigned(static_cast<int32_t>(metadata.key));
+            writeFloat(metadata.value);
+        }
+        endCommand();
+    }
+
+   protected:
+    void beginCommand_2_2(IComposerClient::Command command, uint16_t length) {
+        V2_1::CommandWriterBase::beginCommand(
+            static_cast<V2_1::IComposerClient::Command>(static_cast<int32_t>(command)), length);
+    }
+
+    void writeFloatColor(const IComposerClient::FloatColor& color) {
+        writeFloat(color.r);
+        writeFloat(color.g);
+        writeFloat(color.b);
+        writeFloat(color.a);
+    }
+};
+
+// This class helps parse a command queue.  Note that all sizes/lengths are in
+// units of uint32_t's.
+class CommandReaderBase : public V2_1::CommandReaderBase {
+   public:
+    CommandReaderBase() : V2_1::CommandReaderBase(){};
+
+   protected:
+    IComposerClient::FloatColor readFloatColor() {
+        float r = readFloat();
+        float g = readFloat();
+        float b = readFloat();
+        float a = readFloat();
+        return IComposerClient::FloatColor{r, g, b, a};
+    }
+};
+
+}  // namespace V2_2
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/composer/2.2/vts/functional/Android.bp b/graphics/composer/2.2/vts/functional/Android.bp
new file mode 100644
index 0000000..0325a6c
--- /dev/null
+++ b/graphics/composer/2.2/vts/functional/Android.bp
@@ -0,0 +1,74 @@
+//
+// Copyright (C) 2018 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.
+//
+
+cc_library_static {
+    name: "libVtsHalGraphicsComposerTestUtils@2.2",
+    defaults: ["hidl_defaults"],
+    srcs: [
+        "VtsHalGraphicsComposerTestUtils.cpp",
+    ],
+    shared_libs: [
+        "android.hardware.graphics.composer@2.1",
+        "android.hardware.graphics.composer@2.2",
+        "libfmq",
+        "libsync",
+    ],
+    static_libs: [
+        "libVtsHalGraphicsComposerTestUtils",
+        "VtsHalHidlTargetTestBase",
+    ],
+    header_libs: [
+        "android.hardware.graphics.composer@2.1-command-buffer",
+        "android.hardware.graphics.composer@2.2-command-buffer",
+    ],
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+        "-O0",
+        "-g",
+        "-DLOG_TAG=\"GraphicsComposerTestUtils@2.2\"",
+    ],
+    export_include_dirs: ["include"],
+}
+
+cc_test {
+    name: "VtsHalGraphicsComposerV2_2TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: ["VtsHalGraphicsComposerV2_2TargetTest.cpp"],
+
+    // TODO(b/64437680): Assume these libs are always available on the device.
+    shared_libs: [
+        "libfmq",
+	"libhidltransport",
+        "libsync",
+    ],
+    static_libs: [
+        "android.hardware.graphics.allocator@2.0",
+        "android.hardware.graphics.composer@2.2",
+        "android.hardware.graphics.composer@2.1",
+        "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@2.1",
+        "libVtsHalGraphicsComposerTestUtils",
+        "libVtsHalGraphicsComposerTestUtils@2.2",
+        "libVtsHalGraphicsMapperTestUtils",
+        "libnativehelper",
+    ],
+    header_libs: [
+        "android.hardware.graphics.composer@2.1-command-buffer",
+        "android.hardware.graphics.composer@2.2-command-buffer",
+    ],
+}
diff --git a/graphics/composer/2.2/vts/functional/OWNERS b/graphics/composer/2.2/vts/functional/OWNERS
new file mode 100644
index 0000000..1beb074
--- /dev/null
+++ b/graphics/composer/2.2/vts/functional/OWNERS
@@ -0,0 +1,8 @@
+# Graphics team
+courtneygo@google.com
+olv@google.com
+stoza@google.com
+
+# VTS team
+yim@google.com
+zhuoyao@google.com
diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerTestUtils.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerTestUtils.cpp
new file mode 100644
index 0000000..00946ce
--- /dev/null
+++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerTestUtils.cpp
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2018 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 <VtsHalHidlTargetTestBase.h>
+#include <hidl/HidlTransportUtils.h>
+
+#include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
+#include "2.2/VtsHalGraphicsComposerTestUtils.h"
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_2 {
+namespace tests {
+
+using android::hardware::graphics::composer::V2_2::IComposerClient;
+using android::hardware::details::getDescriptor;
+using android::hardware::details::canCastInterface;
+
+std::unique_ptr<ComposerClient_v2_2> Composer_v2_2::createClient_v2_2() {
+    std::unique_ptr<ComposerClient_v2_2> client;
+    mComposer->createClient([&](const auto& tmpError, const auto& tmpClient) {
+        ASSERT_EQ(Error::NONE, tmpError) << "failed to create client";
+        ALOGV("tmpClient is a %s", getDescriptor(&(*tmpClient)).c_str());
+        ASSERT_TRUE(canCastInterface(
+            &(*tmpClient), "android.hardware.graphics.composer@2.2::IComposerClient", false))
+            << "Cannot create 2.2 IComposerClient";
+        client = std::make_unique<ComposerClient_v2_2>(IComposerClient::castFrom(tmpClient, true));
+    });
+
+    return client;
+}
+
+std::vector<IComposerClient::PerFrameMetadataKey> ComposerClient_v2_2::getPerFrameMetadataKeys(
+    Display display) {
+    std::vector<IComposerClient::PerFrameMetadataKey> keys;
+    mClient_v2_2->getPerFrameMetadataKeys(display, [&](const auto& tmpError, const auto& tmpKeys) {
+        ASSERT_EQ(Error::NONE, tmpError) << "failed to get HDR metadata keys";
+        keys = tmpKeys;
+    });
+
+    return keys;
+}
+
+void ComposerClient_v2_2::execute_v2_2(V2_1::tests::TestCommandReader* reader,
+                                       V2_2::CommandWriterBase* writer) {
+    bool queueChanged = false;
+    uint32_t commandLength = 0;
+    hidl_vec<hidl_handle> commandHandles;
+    ASSERT_TRUE(writer->writeQueue(&queueChanged, &commandLength, &commandHandles));
+
+    if (queueChanged) {
+        auto ret = mClient_v2_2->setInputCommandQueue(*writer->getMQDescriptor());
+        ASSERT_EQ(Error::NONE, static_cast<Error>(ret));
+        return;
+    }
+
+    mClient_v2_2->executeCommands(commandLength, commandHandles,
+                                  [&](const auto& tmpError, const auto& tmpOutQueueChanged,
+                                      const auto& tmpOutLength, const auto& tmpOutHandles) {
+                                      ASSERT_EQ(Error::NONE, tmpError);
+
+                                      if (tmpOutQueueChanged) {
+                                          mClient_v2_2->getOutputCommandQueue(
+                                              [&](const auto& tmpError, const auto& tmpDescriptor) {
+                                                  ASSERT_EQ(Error::NONE, tmpError);
+                                                  reader->setMQDescriptor(tmpDescriptor);
+                                              });
+                                      }
+
+                                      ASSERT_TRUE(reader->readQueue(tmpOutLength, tmpOutHandles));
+                                      reader->parse();
+                                  });
+}
+
+void ComposerClient_v2_2::setPowerMode_2_2(Display display, V2_2::IComposerClient::PowerMode mode) {
+    Error error = mClient_v2_2->setPowerMode_2_2(display, mode);
+    ASSERT_TRUE(error == Error::NONE || error == Error::UNSUPPORTED) << "failed to set power mode";
+}
+
+void ComposerClient_v2_2::setReadbackBuffer(Display display, const native_handle_t* buffer,
+                                            int32_t /* releaseFence */) {
+    // Ignoring fence, HIDL doesn't care
+    Error error = mClient_v2_2->setReadbackBuffer(display, buffer, nullptr);
+    ASSERT_EQ(Error::NONE, error) << "failed to setReadbackBuffer";
+}
+
+void ComposerClient_v2_2::getReadbackBufferAttributes(Display display, PixelFormat* outPixelFormat,
+                                                      Dataspace* outDataspace) {
+    mClient_v2_2->getReadbackBufferAttributes(
+        display,
+        [&](const auto& tmpError, const auto& tmpOutPixelFormat, const auto& tmpOutDataspace) {
+            ASSERT_EQ(Error::NONE, tmpError) << "failed to get readback buffer attributes";
+            *outPixelFormat = tmpOutPixelFormat;
+            *outDataspace = tmpOutDataspace;
+        });
+}
+
+void ComposerClient_v2_2::getReadbackBufferFence(Display display, int32_t* outFence) {
+    hidl_handle handle;
+    mClient_v2_2->getReadbackBufferFence(display, [&](const auto& tmpError, const auto& tmpHandle) {
+        ASSERT_EQ(Error::NONE, tmpError) << "failed to get readback fence";
+        handle = tmpHandle;
+    });
+    *outFence = 0;
+}
+
+}  // namespace tests
+}  // namespace V2_2
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp
new file mode 100644
index 0000000..8b44d61
--- /dev/null
+++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2018 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 "graphics_composer_hidl_hal_test@2.2"
+
+#include <android-base/logging.h>
+#include <android/hardware/graphics/mapper/2.1/IMapper.h>
+#include <sync/sync.h>
+#include "2.2/VtsHalGraphicsComposerTestUtils.h"
+#include "GraphicsComposerCallback.h"
+#include "TestCommandReader.h"
+#include "VtsHalGraphicsComposerTestUtils.h"
+#include "VtsHalGraphicsMapperTestUtils.h"
+
+#include <VtsHalHidlTargetTestBase.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_2 {
+namespace tests {
+namespace {
+
+using android::hardware::graphics::common::V1_0::BufferUsage;
+using android::hardware::graphics::common::V1_0::ColorMode;
+using android::hardware::graphics::common::V1_0::ColorTransform;
+using android::hardware::graphics::common::V1_0::Dataspace;
+using android::hardware::graphics::common::V1_0::PixelFormat;
+using android::hardware::graphics::common::V1_0::Transform;
+using android::hardware::graphics::composer::V2_2::IComposerClient;
+using android::hardware::graphics::mapper::V2_0::IMapper;
+using android::hardware::graphics::mapper::V2_0::tests::Gralloc;
+using GrallocError = android::hardware::graphics::mapper::V2_0::Error;
+
+// Test environment for graphics.composer
+class GraphicsComposerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+   public:
+    // get the test environment singleton
+    static GraphicsComposerHidlEnvironment* Instance() {
+        static GraphicsComposerHidlEnvironment* instance = new GraphicsComposerHidlEnvironment;
+        return instance;
+    }
+
+    virtual void registerTestServices() override { registerTestService<IComposer>(); }
+
+   private:
+    GraphicsComposerHidlEnvironment() {}
+
+    GTEST_DISALLOW_COPY_AND_ASSIGN_(GraphicsComposerHidlEnvironment);
+};
+
+class GraphicsComposerHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+   protected:
+    void SetUp() override {
+        ASSERT_NO_FATAL_FAILURE(
+            mComposer = std::make_unique<Composer_v2_2>(
+                GraphicsComposerHidlEnvironment::Instance()->getServiceName<IComposer>()));
+        ASSERT_NO_FATAL_FAILURE(mComposerClient = mComposer->createClient_v2_2());
+
+        mComposerCallback = new V2_1::tests::GraphicsComposerCallback;
+        mComposerClient->registerCallback(mComposerCallback);
+
+        // assume the first display is primary and is never removed
+        mPrimaryDisplay = waitForFirstDisplay();
+
+        // explicitly disable vsync
+        mComposerClient->setVsyncEnabled(mPrimaryDisplay, false);
+        mComposerCallback->setVsyncAllowed(false);
+    }
+
+    void TearDown() override {
+        if (mComposerCallback != nullptr) {
+            EXPECT_EQ(0, mComposerCallback->getInvalidHotplugCount());
+            EXPECT_EQ(0, mComposerCallback->getInvalidRefreshCount());
+            EXPECT_EQ(0, mComposerCallback->getInvalidVsyncCount());
+        }
+    }
+
+    // use the slot count usually set by SF
+    static constexpr uint32_t kBufferSlotCount = 64;
+
+    std::unique_ptr<Composer_v2_2> mComposer;
+    std::unique_ptr<ComposerClient_v2_2> mComposerClient;
+    sp<V2_1::tests::GraphicsComposerCallback> mComposerCallback;
+    // the first display and is assumed never to be removed
+    Display mPrimaryDisplay;
+
+   private:
+    Display waitForFirstDisplay() {
+        while (true) {
+            std::vector<Display> displays = mComposerCallback->getDisplays();
+            if (displays.empty()) {
+                usleep(5 * 1000);
+                continue;
+            }
+
+            return displays[0];
+        }
+    }
+};
+
+// Tests for IComposerClient::Command.
+class GraphicsComposerHidlCommandTest : public GraphicsComposerHidlTest {
+   protected:
+    void SetUp() override {
+        ASSERT_NO_FATAL_FAILURE(GraphicsComposerHidlTest::SetUp());
+
+        ASSERT_NO_FATAL_FAILURE(mGralloc = std::make_unique<Gralloc>());
+
+        mWriter = std::make_unique<V2_2::CommandWriterBase>(1024);
+        mReader = std::make_unique<V2_1::tests::TestCommandReader>();
+    }
+
+    void TearDown() override { ASSERT_NO_FATAL_FAILURE(GraphicsComposerHidlTest::TearDown()); }
+
+    const native_handle_t* allocate() {
+        IMapper::BufferDescriptorInfo info{};
+        info.width = 64;
+        info.height = 64;
+        info.layerCount = 1;
+        info.format = PixelFormat::RGBA_8888;
+        info.usage =
+            static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN);
+
+        return mGralloc->allocate(info);
+    }
+
+    void execute() { mComposerClient->execute_v2_2(mReader.get(), mWriter.get()); }
+
+    std::unique_ptr<V2_2::CommandWriterBase> mWriter;
+    std::unique_ptr<V2_1::tests::TestCommandReader> mReader;
+
+   private:
+    std::unique_ptr<Gralloc> mGralloc;
+};
+
+/**
+ * Test IComposerClient::Command::SET_PER_FRAME_METADATA.
+ */
+TEST_F(GraphicsComposerHidlCommandTest, SET_PER_FRAME_METADATA) {
+    Layer layer;
+    ASSERT_NO_FATAL_FAILURE(layer =
+                                mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
+
+    mWriter->selectDisplay(mPrimaryDisplay);
+    mWriter->selectLayer(layer);
+
+    /**
+     * DISPLAY_P3 is a color space that uses the DCI_P3 primaries,
+     * the D65 white point and the SRGB transfer functions.
+     * Rendering Intent: Colorimetric
+     * Primaries:
+     *                  x       y
+     *  green           0.265   0.690
+     *  blue            0.150   0.060
+     *  red             0.680   0.320
+     *  white (D65)     0.3127  0.3290
+     */
+
+    std::vector<IComposerClient::PerFrameMetadata> hidlMetadata;
+    hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::DISPLAY_RED_PRIMARY_X, 0.680});
+    hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::DISPLAY_RED_PRIMARY_Y, 0.320});
+    hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::DISPLAY_GREEN_PRIMARY_X, 0.265});
+    hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::DISPLAY_GREEN_PRIMARY_Y, 0.690});
+    hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::DISPLAY_BLUE_PRIMARY_X, 0.150});
+    hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::DISPLAY_BLUE_PRIMARY_Y, 0.060});
+    hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::WHITE_POINT_X, 0.3127});
+    hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::WHITE_POINT_Y, 0.3290});
+    hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::MAX_LUMINANCE, 100.0});
+    hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::MIN_LUMINANCE, 0.1});
+    hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::MAX_CONTENT_LIGHT_LEVEL, 78.0});
+    hidlMetadata.push_back(
+        {IComposerClient::PerFrameMetadataKey::MAX_FRAME_AVERAGE_LIGHT_LEVEL, 62.0});
+    mWriter->setPerFrameMetadata(hidlMetadata);
+    execute();
+}
+
+/**
+ * Test IComposerClient::getPerFrameMetadataKeys.
+ */
+TEST_F(GraphicsComposerHidlTest, GetPerFrameMetadataKeys) {
+    mComposerClient->getPerFrameMetadataKeys(mPrimaryDisplay);
+}
+/**
+ * Test IComposerClient::setPowerMode_2_2.
+ */
+TEST_F(GraphicsComposerHidlTest, setPowerMode_2_2) {
+    std::vector<IComposerClient::PowerMode> modes;
+    modes.push_back(IComposerClient::PowerMode::OFF);
+    modes.push_back(IComposerClient::PowerMode::ON_SUSPEND);
+    modes.push_back(IComposerClient::PowerMode::ON);
+
+    for (auto mode : modes) {
+        mComposerClient->setPowerMode_2_2(mPrimaryDisplay, mode);
+    }
+}
+
+TEST_F(GraphicsComposerHidlTest, setReadbackBuffer) {
+    mComposerClient->setReadbackBuffer(mPrimaryDisplay, nullptr, -1);
+}
+
+TEST_F(GraphicsComposerHidlTest, getReadbackBufferFence) {
+    int32_t fence;
+    mComposerClient->getReadbackBufferFence(mPrimaryDisplay, &fence);
+}
+
+TEST_F(GraphicsComposerHidlTest, getReadbackBufferAttributes) {
+    PixelFormat pixelFormat;
+    Dataspace dataspace;
+    mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, &pixelFormat, &dataspace);
+}
+
+/**
+ * Test IComposerClient::Command::SET_LAYER_FLOAT_COLOR.
+ */
+TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_FLOAT_COLOR) {
+    V2_1::Layer layer;
+    ASSERT_NO_FATAL_FAILURE(layer =
+                                mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
+
+    mWriter->selectDisplay(mPrimaryDisplay);
+    mWriter->selectLayer(layer);
+    mWriter->setLayerFloatColor(IComposerClient::FloatColor{1.0, 1.0, 1.0, 1.0});
+    mWriter->setLayerFloatColor(IComposerClient::FloatColor{0.0, 0.0, 0.0, 0.0});
+}
+
+}  // namespace
+}  // namespace tests
+}  // namespace V2_2
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
+
+int main(int argc, char** argv) {
+    using android::hardware::graphics::composer::V2_2::tests::GraphicsComposerHidlEnvironment;
+    ::testing::AddGlobalTestEnvironment(GraphicsComposerHidlEnvironment::Instance());
+    ::testing::InitGoogleTest(&argc, argv);
+    GraphicsComposerHidlEnvironment::Instance()->init(&argc, argv);
+    int status = RUN_ALL_TESTS();
+    return status;
+}
diff --git a/graphics/composer/2.2/vts/functional/include/2.2/VtsHalGraphicsComposerTestUtils.h b/graphics/composer/2.2/vts/functional/include/2.2/VtsHalGraphicsComposerTestUtils.h
new file mode 100644
index 0000000..c5756ed
--- /dev/null
+++ b/graphics/composer/2.2/vts/functional/include/2.2/VtsHalGraphicsComposerTestUtils.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#pragma once
+
+#include <memory>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+#include <VtsHalGraphicsComposerTestUtils.h>
+#include <VtsHalHidlTargetTestBase.h>
+#include <android/hardware/graphics/composer/2.2/IComposer.h>
+#include <android/hardware/graphics/composer/2.2/IComposerClient.h>
+#include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_2 {
+namespace tests {
+
+using android::hardware::graphics::common::V1_0::ColorMode;
+using android::hardware::graphics::common::V1_0::Dataspace;
+using android::hardware::graphics::common::V1_0::Hdr;
+using android::hardware::graphics::common::V1_0::PixelFormat;
+using android::hardware::graphics::composer::V2_2::IComposer;
+using android::hardware::graphics::composer::V2_2::IComposerClient;
+
+class ComposerClient_v2_2;
+
+// Only thing I need for Composer_v2_2 is to create a v2_2 ComposerClient
+// Everything else is the same
+class Composer_v2_2 : public V2_1::tests::Composer {
+   public:
+    Composer_v2_2() : V2_1::tests::Composer(){};
+    explicit Composer_v2_2(const std::string& name) : V2_1::tests::Composer(name){};
+
+    std::unique_ptr<ComposerClient_v2_2> createClient_v2_2();
+};
+
+// A wrapper to IComposerClient.
+class ComposerClient_v2_2
+    : public android::hardware::graphics::composer::V2_1::tests::ComposerClient {
+   public:
+    ComposerClient_v2_2(const sp<IComposerClient>& client)
+        : V2_1::tests::ComposerClient(client), mClient_v2_2(client){};
+
+    void execute_v2_2(V2_1::tests::TestCommandReader* reader, V2_2::CommandWriterBase* writer);
+
+    std::vector<IComposerClient::PerFrameMetadataKey> getPerFrameMetadataKeys(Display display);
+
+    void setPowerMode_2_2(Display display, V2_2::IComposerClient::PowerMode mode);
+    void setReadbackBuffer(Display display, const native_handle_t* buffer, int32_t releaseFence);
+    void getReadbackBufferAttributes(Display display, PixelFormat* outPixelFormat,
+                                     Dataspace* outDataspace);
+    void getReadbackBufferFence(Display display, int32_t* outFence);
+
+   private:
+    sp<V2_2::IComposerClient> mClient_v2_2;
+};
+
+}  // namespace tests
+}  // namespace V2_2
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/radio/1.0/vts/functional/radio_hidl_hal_voice.cpp b/radio/1.0/vts/functional/radio_hidl_hal_voice.cpp
index b3d5648..d0320b9 100644
--- a/radio/1.0/vts/functional/radio_hidl_hal_voice.cpp
+++ b/radio/1.0/vts/functional/radio_hidl_hal_voice.cpp
@@ -489,4 +489,4 @@
                                       RadioError::MODEM_ERR, RadioError::OPERATION_NOT_ALLOWED},
                                      CHECK_GENERAL_ERROR));
     }
-}
\ No newline at end of file
+}
diff --git a/vibrator/1.2/Android.bp b/vibrator/1.2/Android.bp
new file mode 100644
index 0000000..88192c1
--- /dev/null
+++ b/vibrator/1.2/Android.bp
@@ -0,0 +1,23 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.vibrator@1.2",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "IVibrator.hal",
+    ],
+    interfaces: [
+        "android.hardware.vibrator@1.0",
+        "android.hardware.vibrator@1.1",
+        "android.hidl.base@1.0",
+    ],
+    types: [
+        "Effect",
+    ],
+    gen_java: true,
+}
+
diff --git a/vibrator/1.2/IVibrator.hal b/vibrator/1.2/IVibrator.hal
new file mode 100644
index 0000000..7244da1
--- /dev/null
+++ b/vibrator/1.2/IVibrator.hal
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+package android.hardware.vibrator@1.2;
+
+import @1.0::EffectStrength;
+import @1.0::Status;
+import @1.1::IVibrator;
+
+interface IVibrator extends @1.1::IVibrator {
+  /**
+   * Fire off a predefined haptic event.
+   *
+   * @param event The type of haptic event to trigger.
+   * @return status Whether the effect was successfully performed or not. Must
+   *     return Status::UNSUPPORTED_OPERATION is the effect is not supported.
+   * @return lengthMs The length of time the event is expected to take in
+   *     milliseconds. This doesn't need to be perfectly accurate, but should be a reasonable
+   *     approximation. Should be a positive, non-zero value if the returned status is Status::OK,
+   *     and set to 0 otherwise.
+   */
+  perform_1_2(Effect effect, EffectStrength strength)
+          generates (Status status, uint32_t lengthMs);
+};
diff --git a/vibrator/1.2/types.hal b/vibrator/1.2/types.hal
new file mode 100644
index 0000000..7604f2c
--- /dev/null
+++ b/vibrator/1.2/types.hal
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+package android.hardware.vibrator@1.2;
+
+import @1.1::Effect_1_1;
+
+// Note that while the previous type had a version suffix, this type does not. This is because the
+// versions are already present in the namespace and thus don't need to also be embedded in the
+// name of the type.
+enum Effect : @1.1::Effect_1_1 {
+     /**
+      * A thud effect.
+      *
+      * This effect should solid feeling bump, like the depression of a heavy mechanical button.
+      */
+     THUD,
+     /**
+      * A pop effect.
+      *
+      * A short, quick burst effect.
+      */
+     POP,
+
+     /**
+      * A heavy click effect.
+      *
+      * This should produce a sharp striking sensation, like a click but stronger.
+      */
+     HEAVY_CLICK,
+
+     /**
+      * Ringtone patterns. They may correspond with the device's ringtone audio, or may just be a
+      * pattern that can be played as a ringtone with any audio, depending on the device.
+      */
+     RINGTONE_1,
+     RINGTONE_2,
+     RINGTONE_3,
+     RINGTONE_4,
+     RINGTONE_5,
+     RINGTONE_6,
+     RINGTONE_7,
+     RINGTONE_8,
+     RINGTONE_9,
+     RINGTONE_10,
+     RINGTONE_11,
+     RINGTONE_12,
+     RINGTONE_13,
+     RINGTONE_14,
+     RINGTONE_15,
+};
diff --git a/vibrator/1.2/vts/functional/Android.bp b/vibrator/1.2/vts/functional/Android.bp
new file mode 100644
index 0000000..3a4e2ef
--- /dev/null
+++ b/vibrator/1.2/vts/functional/Android.bp
@@ -0,0 +1,27 @@
+//
+// Copyright (C) 2018 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.
+//
+
+cc_test {
+    name: "VtsHalVibratorV1_2TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: ["VtsHalVibratorV1_2TargetTest.cpp"],
+    static_libs: [
+        "android.hardware.vibrator@1.0",
+        "android.hardware.vibrator@1.1",
+        "android.hardware.vibrator@1.2",
+    ],
+}
+
diff --git a/vibrator/1.2/vts/functional/VtsHalVibratorV1_2TargetTest.cpp b/vibrator/1.2/vts/functional/VtsHalVibratorV1_2TargetTest.cpp
new file mode 100644
index 0000000..d07d1b7
--- /dev/null
+++ b/vibrator/1.2/vts/functional/VtsHalVibratorV1_2TargetTest.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2018 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 "vibrator_hidl_hal_test"
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <android-base/logging.h>
+#include <android/hardware/vibrator/1.0/types.h>
+#include <android/hardware/vibrator/1.2/IVibrator.h>
+#include <android/hardware/vibrator/1.2/types.h>
+#include <unistd.h>
+
+using ::android::hardware::vibrator::V1_0::Status;
+using ::android::hardware::vibrator::V1_0::EffectStrength;
+using ::android::hardware::vibrator::V1_2::Effect;
+using ::android::hardware::vibrator::V1_2::IVibrator;
+using ::android::hardware::hidl_enum_iterator;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+// The main test class for VIBRATOR HIDL HAL 1.2.
+class VibratorHidlTest_1_2 : public ::testing::VtsHalHidlTargetTestBase {
+   public:
+    virtual void SetUp() override {
+        vibrator = ::testing::VtsHalHidlTargetTestBase::getService<IVibrator>();
+        ASSERT_NE(vibrator, nullptr);
+    }
+
+    virtual void TearDown() override {}
+
+    sp<IVibrator> vibrator;
+};
+
+static void validatePerformEffect(Status status, uint32_t lengthMs) {
+    ASSERT_TRUE(status == Status::OK || status == Status::UNSUPPORTED_OPERATION);
+    if (status == Status::OK) {
+        ASSERT_GT(lengthMs, static_cast<uint32_t>(0))
+            << "Effects that return OK must return a non-zero duration";
+    } else {
+        ASSERT_EQ(lengthMs, static_cast<uint32_t>(0))
+            << "Effects that return UNSUPPORTED_OPERATION must have a duration of zero";
+    }
+}
+
+TEST_F(VibratorHidlTest_1_2, PerformEffect_1_2) {
+    for (const auto& effect : hidl_enum_iterator<Effect>()) {
+        for (const auto& strength : hidl_enum_iterator<EffectStrength>()) {
+            vibrator->perform_1_2(effect, strength, validatePerformEffect);
+        }
+    }
+}
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    int status = RUN_ALL_TESTS();
+    LOG(INFO) << "Test result = " << status;
+    return status;
+}
diff --git a/wifi/1.2/default/wifi.cpp b/wifi/1.2/default/wifi.cpp
index d6106b4..79f921f 100644
--- a/wifi/1.2/default/wifi.cpp
+++ b/wifi/1.2/default/wifi.cpp
@@ -80,6 +80,9 @@
 Return<void> Wifi::debug(const hidl_handle& handle,
                          const hidl_vec<hidl_string>&) {
     LOG(INFO) << "-----------Debug is called----------------";
+    if (!chip_.get()) {
+        return Void();
+    }
     return chip_->debug(handle, {});
 }