Merge "Log dlerror on dlopen related failures"
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/camera/device/3.2/default/CameraDeviceSession.cpp b/camera/device/3.2/default/CameraDeviceSession.cpp
index ae275ae..975fb01 100644
--- a/camera/device/3.2/default/CameraDeviceSession.cpp
+++ b/camera/device/3.2/default/CameraDeviceSession.cpp
@@ -1198,26 +1198,19 @@
     return Void();
 }
 
-/**
- * Static callback forwarding methods from HAL to instance
- */
-void CameraDeviceSession::sProcessCaptureResult(
-        const camera3_callback_ops *cb,
-        const camera3_capture_result *hal_result) {
-    CameraDeviceSession *d =
-            const_cast<CameraDeviceSession*>(static_cast<const CameraDeviceSession*>(cb));
-
+void CameraDeviceSession::constructCaptureResult(CaptureResult& result,
+                                                 const camera3_capture_result *hal_result) {
     uint32_t frameNumber = hal_result->frame_number;
     bool hasInputBuf = (hal_result->input_buffer != nullptr);
     size_t numOutputBufs = hal_result->num_output_buffers;
     size_t numBufs = numOutputBufs + (hasInputBuf ? 1 : 0);
     if (numBufs > 0) {
-        Mutex::Autolock _l(d->mInflightLock);
+        Mutex::Autolock _l(mInflightLock);
         if (hasInputBuf) {
             int streamId = static_cast<Camera3Stream*>(hal_result->input_buffer->stream)->mId;
             // validate if buffer is inflight
             auto key = std::make_pair(streamId, frameNumber);
-            if (d->mInflightBuffers.count(key) != 1) {
+            if (mInflightBuffers.count(key) != 1) {
                 ALOGE("%s: input buffer for stream %d frame %d is not inflight!",
                         __FUNCTION__, streamId, frameNumber);
                 return;
@@ -1228,7 +1221,7 @@
             int streamId = static_cast<Camera3Stream*>(hal_result->output_buffers[i].stream)->mId;
             // validate if buffer is inflight
             auto key = std::make_pair(streamId, frameNumber);
-            if (d->mInflightBuffers.count(key) != 1) {
+            if (mInflightBuffers.count(key) != 1) {
                 ALOGE("%s: output buffer for stream %d frame %d is not inflight!",
                         __FUNCTION__, streamId, frameNumber);
                 return;
@@ -1237,64 +1230,63 @@
     }
     // We don't need to validate/import fences here since we will be passing them to camera service
     // within the scope of this function
-    CaptureResult result;
     result.frameNumber = frameNumber;
     result.fmqResultSize = 0;
     result.partialResult = hal_result->partial_result;
     convertToHidl(hal_result->result, &result.result);
     if (nullptr != hal_result->result) {
         bool resultOverriden = false;
-        Mutex::Autolock _l(d->mInflightLock);
+        Mutex::Autolock _l(mInflightLock);
 
         // Derive some new keys for backward compatibility
-        if (d->mDerivePostRawSensKey) {
+        if (mDerivePostRawSensKey) {
             camera_metadata_ro_entry entry;
             if (find_camera_metadata_ro_entry(hal_result->result,
                     ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST, &entry) == 0) {
-                d->mInflightRawBoostPresent[frameNumber] = true;
+                mInflightRawBoostPresent[frameNumber] = true;
             } else {
-                auto entry = d->mInflightRawBoostPresent.find(frameNumber);
-                if (d->mInflightRawBoostPresent.end() == entry) {
-                    d->mInflightRawBoostPresent[frameNumber] = false;
+                auto entry = mInflightRawBoostPresent.find(frameNumber);
+                if (mInflightRawBoostPresent.end() == entry) {
+                    mInflightRawBoostPresent[frameNumber] = false;
                 }
             }
 
-            if ((hal_result->partial_result == d->mNumPartialResults)) {
-                if (!d->mInflightRawBoostPresent[frameNumber]) {
+            if ((hal_result->partial_result == mNumPartialResults)) {
+                if (!mInflightRawBoostPresent[frameNumber]) {
                     if (!resultOverriden) {
-                        d->mOverridenResult.clear();
-                        d->mOverridenResult.append(hal_result->result);
+                        mOverridenResult.clear();
+                        mOverridenResult.append(hal_result->result);
                         resultOverriden = true;
                     }
                     int32_t defaultBoost[1] = {100};
-                    d->mOverridenResult.update(
+                    mOverridenResult.update(
                             ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST,
                             defaultBoost, 1);
                 }
 
-                d->mInflightRawBoostPresent.erase(frameNumber);
+                mInflightRawBoostPresent.erase(frameNumber);
             }
         }
 
-        auto entry = d->mInflightAETriggerOverrides.find(frameNumber);
-        if (d->mInflightAETriggerOverrides.end() != entry) {
+        auto entry = mInflightAETriggerOverrides.find(frameNumber);
+        if (mInflightAETriggerOverrides.end() != entry) {
             if (!resultOverriden) {
-                d->mOverridenResult.clear();
-                d->mOverridenResult.append(hal_result->result);
+                mOverridenResult.clear();
+                mOverridenResult.append(hal_result->result);
                 resultOverriden = true;
             }
-            d->overrideResultForPrecaptureCancelLocked(entry->second,
-                    &d->mOverridenResult);
-            if (hal_result->partial_result == d->mNumPartialResults) {
-                d->mInflightAETriggerOverrides.erase(frameNumber);
+            overrideResultForPrecaptureCancelLocked(entry->second,
+                    &mOverridenResult);
+            if (hal_result->partial_result == mNumPartialResults) {
+                mInflightAETriggerOverrides.erase(frameNumber);
             }
         }
 
         if (resultOverriden) {
             const camera_metadata_t *metaBuffer =
-                    d->mOverridenResult.getAndLock();
+                    mOverridenResult.getAndLock();
             convertToHidl(metaBuffer, &result.result);
-            d->mOverridenResult.unlock(metaBuffer);
+            mOverridenResult.unlock(metaBuffer);
         }
     }
     if (hasInputBuf) {
@@ -1335,24 +1327,38 @@
     // configure_streams right after the processCaptureResult call so we need to finish
     // updating inflight queues first
     if (numBufs > 0) {
-        Mutex::Autolock _l(d->mInflightLock);
+        Mutex::Autolock _l(mInflightLock);
         if (hasInputBuf) {
             int streamId = static_cast<Camera3Stream*>(hal_result->input_buffer->stream)->mId;
             auto key = std::make_pair(streamId, frameNumber);
-            d->mInflightBuffers.erase(key);
+            mInflightBuffers.erase(key);
         }
 
         for (size_t i = 0; i < numOutputBufs; i++) {
             int streamId = static_cast<Camera3Stream*>(hal_result->output_buffers[i].stream)->mId;
             auto key = std::make_pair(streamId, frameNumber);
-            d->mInflightBuffers.erase(key);
+            mInflightBuffers.erase(key);
         }
 
-        if (d->mInflightBuffers.empty()) {
+        if (mInflightBuffers.empty()) {
             ALOGV("%s: inflight buffer queue is now empty!", __FUNCTION__);
         }
     }
 
+}
+
+/**
+ * Static callback forwarding methods from HAL to instance
+ */
+void CameraDeviceSession::sProcessCaptureResult(
+        const camera3_callback_ops *cb,
+        const camera3_capture_result *hal_result) {
+    CameraDeviceSession *d =
+            const_cast<CameraDeviceSession*>(static_cast<const CameraDeviceSession*>(cb));
+
+    CaptureResult result;
+    d->constructCaptureResult(result, hal_result);
+
     d->mResultBatcher.processCaptureResult(result);
 }
 
diff --git a/camera/device/3.2/default/CameraDeviceSession.h b/camera/device/3.2/default/CameraDeviceSession.h
index dd73b39..61db671 100644
--- a/camera/device/3.2/default/CameraDeviceSession.h
+++ b/camera/device/3.2/default/CameraDeviceSession.h
@@ -190,7 +190,7 @@
         void notify(NotifyMsg& msg);
         void processCaptureResult(CaptureResult& result);
 
-    private:
+    protected:
         struct InflightBatch {
             // Protect access to entire struct. Acquire this lock before read/write any data or
             // calling any methods. processCaptureResult and notify will compete for this lock
@@ -235,7 +235,6 @@
             bool mRemoved = false;
         };
 
-        static const int NOT_BATCHED = -1;
 
         // Get the batch index and pointer to InflightBatch (nullptrt if the frame is not batched)
         // Caller must acquire the InflightBatch::mLock before accessing the InflightBatch
@@ -245,6 +244,16 @@
         // This method will hold ResultBatcher::mLock briefly
         std::pair<int, std::shared_ptr<InflightBatch>> getBatch(uint32_t frameNumber);
 
+        static const int NOT_BATCHED = -1;
+
+        // move/push function avoids "hidl_handle& operator=(hidl_handle&)", which clones native
+        // handle
+        void moveStreamBuffer(StreamBuffer&& src, StreamBuffer& dst);
+        void pushStreamBuffer(StreamBuffer&& src, std::vector<StreamBuffer>& dst);
+
+        void sendBatchMetadataLocked(
+                std::shared_ptr<InflightBatch> batch, uint32_t lastPartialResultIdx);
+
         // Check if the first batch in mInflightBatches is ready to be removed, and remove it if so
         // This method will hold ResultBatcher::mLock briefly
         void checkAndRemoveFirstBatch();
@@ -257,9 +266,7 @@
         // send buffers for specified streams
         void sendBatchBuffersLocked(
                 std::shared_ptr<InflightBatch> batch, const std::vector<int>& streams);
-        void sendBatchMetadataLocked(
-                std::shared_ptr<InflightBatch> batch, uint32_t lastPartialResultIdx);
-        // End of sendXXXX methods
+       // End of sendXXXX methods
 
         // helper methods
         void freeReleaseFences(hidl_vec<CaptureResult>&);
@@ -267,11 +274,6 @@
         void processOneCaptureResult(CaptureResult& result);
         void invokeProcessCaptureResultCallback(hidl_vec<CaptureResult> &results, bool tryWriteFmq);
 
-        // move/push function avoids "hidl_handle& operator=(hidl_handle&)", which clones native
-        // handle
-        void moveStreamBuffer(StreamBuffer&& src, StreamBuffer& dst);
-        void pushStreamBuffer(StreamBuffer&& src, std::vector<StreamBuffer>& dst);
-
         // Protect access to mInflightBatches, mNumPartialResults and mStreamsToBatch
         // processCaptureRequest, processCaptureResult, notify will compete for this lock
         // Do NOT issue HIDL IPCs while holding this lock (except when HAL reports error)
@@ -325,6 +327,8 @@
     static callbacks_process_capture_result_t sProcessCaptureResult;
     static callbacks_notify_t sNotify;
 
+    void constructCaptureResult(CaptureResult& result,
+                                const camera3_capture_result *hal_result);
 private:
 
     struct TrampolineSessionInterface_3_2 : public ICameraDeviceSession {
diff --git a/camera/device/3.4/Android.bp b/camera/device/3.4/Android.bp
index b3757c0..87acd25 100644
--- a/camera/device/3.4/Android.bp
+++ b/camera/device/3.4/Android.bp
@@ -8,6 +8,7 @@
     },
     srcs: [
         "types.hal",
+        "ICameraDeviceCallback.hal",
         "ICameraDeviceSession.hal",
     ],
     interfaces: [
@@ -19,8 +20,10 @@
     ],
     types: [
         "CaptureRequest",
+        "CaptureResult",
         "HalStream",
         "HalStreamConfiguration",
+        "PhysicalCameraMetadata",
         "PhysicalCameraSetting",
         "RequestTemplate",
         "Stream",
diff --git a/camera/device/3.4/ICameraDeviceCallback.hal b/camera/device/3.4/ICameraDeviceCallback.hal
new file mode 100644
index 0000000..8ce8d4b
--- /dev/null
+++ b/camera/device/3.4/ICameraDeviceCallback.hal
@@ -0,0 +1,43 @@
+/*
+ * 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.camera.device@3.4;
+
+import @3.2::ICameraDeviceCallback;
+
+/**
+ *
+ * Callback methods for the HAL to call into the framework.
+ *
+ * These methods are used to return metadata and image buffers for a completed
+ * or failed captures, and to notify the framework of asynchronous events such
+ * as errors.
+ *
+ * The framework must not call back into the HAL from within these callbacks,
+ * and these calls must not block for extended periods.
+ *
+ */
+interface ICameraDeviceCallback extends @3.2::ICameraDeviceCallback {
+    /**
+     * processCaptureResult_3_4:
+     *
+     * Identical to @3.2::ICameraDeviceCallback.processCaptureResult, except
+     * that it takes a list of @3.4::CaptureResult, which could contain
+     * physical camera metadata for logical multi-camera.
+     *
+     */
+    processCaptureResult_3_4(vec<@3.4::CaptureResult> results);
+};
diff --git a/camera/device/3.4/default/CameraDeviceSession.cpp b/camera/device/3.4/default/CameraDeviceSession.cpp
index d054788..f6c6b2b 100644
--- a/camera/device/3.4/default/CameraDeviceSession.cpp
+++ b/camera/device/3.4/default/CameraDeviceSession.cpp
@@ -34,7 +34,23 @@
     camera3_device_t* device,
     const camera_metadata_t* deviceInfo,
     const sp<V3_2::ICameraDeviceCallback>& callback) :
-        V3_3::implementation::CameraDeviceSession(device, deviceInfo, callback) {
+        V3_3::implementation::CameraDeviceSession(device, deviceInfo, callback),
+        mResultBatcher_3_4(callback) {
+
+    mHasCallback_3_4 = false;
+
+    auto castResult = ICameraDeviceCallback::castFrom(callback);
+    if (castResult.isOk()) {
+        sp<ICameraDeviceCallback> callback3_4 = castResult;
+        if (callback3_4 != nullptr) {
+            process_capture_result = sProcessCaptureResult_3_4;
+            notify = sNotify_3_4;
+            mHasCallback_3_4 = true;
+            if (!mInitFail) {
+                mResultBatcher_3_4.setResultMetadataQueue(mResultMetadataQueue);
+            }
+        }
+    }
 }
 
 CameraDeviceSession::~CameraDeviceSession() {
@@ -54,6 +70,18 @@
     Status status = initStatus();
     HalStreamConfiguration outStreams;
 
+    // If callback is 3.2, make sure no physical stream is configured
+    if (!mHasCallback_3_4) {
+        for (size_t i = 0; i < requestedConfiguration.streams.size(); i++) {
+            if (requestedConfiguration.streams[i].physicalCameraId.size() > 0) {
+                ALOGE("%s: trying to configureStreams with physical camera id with V3.2 callback",
+                        __FUNCTION__);
+                _hidl_cb(Status::INTERNAL_ERROR, outStreams);
+                return Void();
+            }
+        }
+    }
+
     // hold the inflight lock for entire configureStreams scope since there must not be any
     // inflight request/results during stream configuration.
     Mutex::Autolock _l(mInflightLock);
@@ -205,7 +233,7 @@
             mVideoStreamIds.push_back(stream.v3_2.id);
         }
     }
-    mResultBatcher.setBatchedStreams(mVideoStreamIds);
+    mResultBatcher_3_4.setBatchedStreams(mVideoStreamIds);
 }
 
 Return<void> CameraDeviceSession::processCaptureRequest_3_4(
@@ -224,7 +252,7 @@
     }
 
     if (s == Status::OK && requests.size() > 1) {
-        mResultBatcher.registerBatch(requests[0].v3_2.frameNumber, requests.size());
+        mResultBatcher_3_4.registerBatch(requests[0].v3_2.frameNumber, requests.size());
     }
 
     _hidl_cb(s, numRequestProcessed);
@@ -237,6 +265,14 @@
         ALOGE("%s: camera init failed or disconnected", __FUNCTION__);
         return status;
     }
+    // If callback is 3.2, make sure there are no physical settings.
+    if (!mHasCallback_3_4) {
+        if (request.physicalCameraSettings.size() > 0) {
+            ALOGE("%s: trying to call processCaptureRequest_3_4 with physical camera id "
+                    "and V3.2 callback", __FUNCTION__);
+            return Status::INTERNAL_ERROR;
+        }
+    }
 
     camera3_capture_request_t halRequest;
     halRequest.frame_number = request.v3_2.frameNumber;
@@ -407,6 +443,228 @@
     return Status::OK;
 }
 
+/**
+ * Static callback forwarding methods from HAL to instance
+ */
+void CameraDeviceSession::sProcessCaptureResult_3_4(
+        const camera3_callback_ops *cb,
+        const camera3_capture_result *hal_result) {
+    CameraDeviceSession *d =
+            const_cast<CameraDeviceSession*>(static_cast<const CameraDeviceSession*>(cb));
+
+    CaptureResult result;
+    d->constructCaptureResult(result.v3_2, hal_result);
+    result.physicalCameraMetadata.resize(hal_result->num_physcam_metadata);
+    for (uint32_t i = 0; i < hal_result->num_physcam_metadata; i++) {
+        std::string physicalId = hal_result->physcam_ids[i];
+        V3_2::CameraMetadata physicalMetadata;
+        V3_2::implementation::convertToHidl(hal_result->physcam_metadata[i], &physicalMetadata);
+        PhysicalCameraMetadata physicalCameraMetadata = {
+                .fmqMetadataSize = 0,
+                .physicalCameraId = physicalId,
+                .metadata = physicalMetadata };
+        result.physicalCameraMetadata[i] = physicalCameraMetadata;
+    }
+    d->mResultBatcher_3_4.processCaptureResult_3_4(result);
+}
+
+void CameraDeviceSession::sNotify_3_4(
+        const camera3_callback_ops *cb,
+        const camera3_notify_msg *msg) {
+    CameraDeviceSession *d =
+            const_cast<CameraDeviceSession*>(static_cast<const CameraDeviceSession*>(cb));
+    V3_2::NotifyMsg hidlMsg;
+    V3_2::implementation::convertToHidl(msg, &hidlMsg);
+
+    if (hidlMsg.type == (V3_2::MsgType) CAMERA3_MSG_ERROR &&
+            hidlMsg.msg.error.errorStreamId != -1) {
+        if (d->mStreamMap.count(hidlMsg.msg.error.errorStreamId) != 1) {
+            ALOGE("%s: unknown stream ID %d reports an error!",
+                    __FUNCTION__, hidlMsg.msg.error.errorStreamId);
+            return;
+        }
+    }
+
+    if (static_cast<camera3_msg_type_t>(hidlMsg.type) == CAMERA3_MSG_ERROR) {
+        switch (hidlMsg.msg.error.errorCode) {
+            case V3_2::ErrorCode::ERROR_DEVICE:
+            case V3_2::ErrorCode::ERROR_REQUEST:
+            case V3_2::ErrorCode::ERROR_RESULT: {
+                Mutex::Autolock _l(d->mInflightLock);
+                auto entry = d->mInflightAETriggerOverrides.find(
+                        hidlMsg.msg.error.frameNumber);
+                if (d->mInflightAETriggerOverrides.end() != entry) {
+                    d->mInflightAETriggerOverrides.erase(
+                            hidlMsg.msg.error.frameNumber);
+                }
+
+                auto boostEntry = d->mInflightRawBoostPresent.find(
+                        hidlMsg.msg.error.frameNumber);
+                if (d->mInflightRawBoostPresent.end() != boostEntry) {
+                    d->mInflightRawBoostPresent.erase(
+                            hidlMsg.msg.error.frameNumber);
+                }
+
+            }
+                break;
+            case V3_2::ErrorCode::ERROR_BUFFER:
+            default:
+                break;
+        }
+
+    }
+
+    d->mResultBatcher_3_4.notify(hidlMsg);
+}
+
+CameraDeviceSession::ResultBatcher_3_4::ResultBatcher_3_4(
+        const sp<V3_2::ICameraDeviceCallback>& callback) :
+        V3_3::implementation::CameraDeviceSession::ResultBatcher(callback) {
+    auto castResult = ICameraDeviceCallback::castFrom(callback);
+    if (castResult.isOk()) {
+        mCallback_3_4 = castResult;
+    }
+}
+
+void CameraDeviceSession::ResultBatcher_3_4::processCaptureResult_3_4(CaptureResult& result) {
+    auto pair = getBatch(result.v3_2.frameNumber);
+    int batchIdx = pair.first;
+    if (batchIdx == NOT_BATCHED) {
+        processOneCaptureResult_3_4(result);
+        return;
+    }
+    std::shared_ptr<InflightBatch> batch = pair.second;
+    {
+        Mutex::Autolock _l(batch->mLock);
+        // Check if the batch is removed (mostly by notify error) before lock was acquired
+        if (batch->mRemoved) {
+            // Fall back to non-batch path
+            processOneCaptureResult_3_4(result);
+            return;
+        }
+
+        // queue metadata
+        if (result.v3_2.result.size() != 0) {
+            // Save a copy of metadata
+            batch->mResultMds[result.v3_2.partialResult].mMds.push_back(
+                    std::make_pair(result.v3_2.frameNumber, result.v3_2.result));
+        }
+
+        // queue buffer
+        std::vector<int> filledStreams;
+        std::vector<V3_2::StreamBuffer> nonBatchedBuffers;
+        for (auto& buffer : result.v3_2.outputBuffers) {
+            auto it = batch->mBatchBufs.find(buffer.streamId);
+            if (it != batch->mBatchBufs.end()) {
+                InflightBatch::BufferBatch& bb = it->second;
+                pushStreamBuffer(std::move(buffer), bb.mBuffers);
+                filledStreams.push_back(buffer.streamId);
+            } else {
+                pushStreamBuffer(std::move(buffer), nonBatchedBuffers);
+            }
+        }
+
+        // send non-batched buffers up
+        if (nonBatchedBuffers.size() > 0 || result.v3_2.inputBuffer.streamId != -1) {
+            CaptureResult nonBatchedResult;
+            nonBatchedResult.v3_2.frameNumber = result.v3_2.frameNumber;
+            nonBatchedResult.v3_2.fmqResultSize = 0;
+            nonBatchedResult.v3_2.outputBuffers.resize(nonBatchedBuffers.size());
+            for (size_t i = 0; i < nonBatchedBuffers.size(); i++) {
+                moveStreamBuffer(
+                        std::move(nonBatchedBuffers[i]), nonBatchedResult.v3_2.outputBuffers[i]);
+            }
+            moveStreamBuffer(std::move(result.v3_2.inputBuffer), nonBatchedResult.v3_2.inputBuffer);
+            nonBatchedResult.v3_2.partialResult = 0; // 0 for buffer only results
+            processOneCaptureResult_3_4(nonBatchedResult);
+        }
+
+        if (result.v3_2.frameNumber == batch->mLastFrame) {
+            // Send data up
+            if (result.v3_2.partialResult > 0) {
+                sendBatchMetadataLocked(batch, result.v3_2.partialResult);
+            }
+            // send buffer up
+            if (filledStreams.size() > 0) {
+                sendBatchBuffersLocked(batch, filledStreams);
+            }
+        }
+    } // end of batch lock scope
+
+    // see if the batch is complete
+    if (result.v3_2.frameNumber == batch->mLastFrame) {
+        checkAndRemoveFirstBatch();
+    }
+}
+
+void CameraDeviceSession::ResultBatcher_3_4::processOneCaptureResult_3_4(CaptureResult& result) {
+    hidl_vec<CaptureResult> results;
+    results.resize(1);
+    results[0] = std::move(result);
+    invokeProcessCaptureResultCallback_3_4(results, /* tryWriteFmq */true);
+    freeReleaseFences_3_4(results);
+    return;
+}
+
+void CameraDeviceSession::ResultBatcher_3_4::invokeProcessCaptureResultCallback_3_4(
+        hidl_vec<CaptureResult> &results, bool tryWriteFmq) {
+    if (mProcessCaptureResultLock.tryLock() != OK) {
+        ALOGV("%s: previous call is not finished! waiting 1s...", __FUNCTION__);
+        if (mProcessCaptureResultLock.timedLock(1000000000 /* 1s */) != OK) {
+            ALOGE("%s: cannot acquire lock in 1s, cannot proceed",
+                    __FUNCTION__);
+            return;
+        }
+    }
+    if (tryWriteFmq && mResultMetadataQueue->availableToWrite() > 0) {
+        for (CaptureResult &result : results) {
+            if (result.v3_2.result.size() > 0) {
+                if (mResultMetadataQueue->write(result.v3_2.result.data(),
+                        result.v3_2.result.size())) {
+                    result.v3_2.fmqResultSize = result.v3_2.result.size();
+                    result.v3_2.result.resize(0);
+                } else {
+                    ALOGW("%s: couldn't utilize fmq, fall back to hwbinder", __FUNCTION__);
+                    result.v3_2.fmqResultSize = 0;
+                }
+            }
+
+            for (auto& onePhysMetadata : result.physicalCameraMetadata) {
+                if (mResultMetadataQueue->write(onePhysMetadata.metadata.data(),
+                        onePhysMetadata.metadata.size())) {
+                    onePhysMetadata.fmqMetadataSize = onePhysMetadata.metadata.size();
+                    onePhysMetadata.metadata.resize(0);
+                } else {
+                    ALOGW("%s: couldn't utilize fmq, fall back to hwbinder", __FUNCTION__);
+                    onePhysMetadata.fmqMetadataSize = 0;
+                }
+            }
+        }
+    }
+    mCallback_3_4->processCaptureResult_3_4(results);
+    mProcessCaptureResultLock.unlock();
+}
+
+void CameraDeviceSession::ResultBatcher_3_4::freeReleaseFences_3_4(hidl_vec<CaptureResult>& results) {
+    for (auto& result : results) {
+        if (result.v3_2.inputBuffer.releaseFence.getNativeHandle() != nullptr) {
+            native_handle_t* handle = const_cast<native_handle_t*>(
+                    result.v3_2.inputBuffer.releaseFence.getNativeHandle());
+            native_handle_close(handle);
+            native_handle_delete(handle);
+        }
+        for (auto& buf : result.v3_2.outputBuffers) {
+            if (buf.releaseFence.getNativeHandle() != nullptr) {
+                native_handle_t* handle = const_cast<native_handle_t*>(
+                        buf.releaseFence.getNativeHandle());
+                native_handle_close(handle);
+                native_handle_delete(handle);
+            }
+        }
+    }
+    return;
+}
+
 } // namespace implementation
 }  // namespace V3_4
 }  // namespace device
diff --git a/camera/device/3.4/default/include/device_v3_4_impl/CameraDeviceSession.h b/camera/device/3.4/default/include/device_v3_4_impl/CameraDeviceSession.h
index 913bd78..9cd7da7 100644
--- a/camera/device/3.4/default/include/device_v3_4_impl/CameraDeviceSession.h
+++ b/camera/device/3.4/default/include/device_v3_4_impl/CameraDeviceSession.h
@@ -19,6 +19,7 @@
 
 #include <android/hardware/camera/device/3.2/ICameraDevice.h>
 #include <android/hardware/camera/device/3.4/ICameraDeviceSession.h>
+#include <android/hardware/camera/device/3.4/ICameraDeviceCallback.h>
 #include <../../3.3/default/CameraDeviceSession.h>
 #include <../../3.3/default/include/convert.h>
 #include <fmq/MessageQueue.h>
@@ -46,6 +47,7 @@
 using ::android::hardware::camera::device::V3_4::StreamConfiguration;
 using ::android::hardware::camera::device::V3_4::HalStreamConfiguration;
 using ::android::hardware::camera::device::V3_4::ICameraDeviceSession;
+using ::android::hardware::camera::device::V3_4::ICameraDeviceCallback;
 using ::android::hardware::camera::common::V1_0::Status;
 using ::android::hardware::camera::common::V1_0::helper::HandleImporter;
 using ::android::hardware::kSynchronizedReadWrite;
@@ -94,6 +96,25 @@
     Status processOneCaptureRequest_3_4(const V3_4::CaptureRequest& request);
 
     std::map<int, std::string> mPhysicalCameraIdMap;
+
+    static V3_2::implementation::callbacks_process_capture_result_t sProcessCaptureResult_3_4;
+    static V3_2::implementation::callbacks_notify_t sNotify_3_4;
+
+    class ResultBatcher_3_4 : public V3_3::implementation::CameraDeviceSession::ResultBatcher {
+    public:
+        ResultBatcher_3_4(const sp<V3_2::ICameraDeviceCallback>& callback);
+        void processCaptureResult_3_4(CaptureResult& result);
+    private:
+        void freeReleaseFences_3_4(hidl_vec<CaptureResult>&);
+        void processOneCaptureResult_3_4(CaptureResult& result);
+        void invokeProcessCaptureResultCallback_3_4(hidl_vec<CaptureResult> &results,
+                bool tryWriteFmq);
+
+        sp<ICameraDeviceCallback> mCallback_3_4;
+    } mResultBatcher_3_4;
+
+    // Whether this camera device session is created with version 3.4 callback.
+    bool mHasCallback_3_4;
 private:
 
     struct TrampolineSessionInterface_3_4 : public ICameraDeviceSession {
diff --git a/camera/device/3.4/types.hal b/camera/device/3.4/types.hal
index 429db3e..5ab6b88 100644
--- a/camera/device/3.4/types.hal
+++ b/camera/device/3.4/types.hal
@@ -22,6 +22,7 @@
 import @3.3::HalStream;
 import @3.2::CameraMetadata;
 import @3.2::CaptureRequest;
+import @3.2::CaptureResult;
 
 /**
  * Stream:
@@ -226,3 +227,66 @@
      */
     vec<PhysicalCameraSetting> physicalCameraSettings;
 };
+
+/**
+ * PhysicalCameraMetadata:
+ *
+ * Individual camera metadata for a physical camera as part of a logical
+ * multi-camera. Camera HAL should return one such metadata for each physical
+ * camera being requested on.
+ */
+struct PhysicalCameraMetadata {
+    /**
+     * If non-zero, read metadata from result metadata queue instead
+     * (see ICameraDeviceSession.getCaptureResultMetadataQueue).
+     * If zero, read metadata from .metadata field.
+     */
+    uint64_t fmqMetadataSize;
+
+    /**
+     * Contains the physical device camera id. As long as the corresponding
+     * processCaptureRequest requests on a particular physical camera stream,
+     * the metadata for that physical camera should be generated for the capture
+     * result. */
+    string physicalCameraId;
+
+    /**
+     * If fmqMetadataSize is zero, the metadata buffer contains the metadata
+     * for the physical device with physicalCameraId.
+     *
+     * The v3_2 CaptureResult metadata is read first from the FMQ, followed by
+     * the physical cameras' metadata starting from index 0.
+     */
+    CameraMetadata metadata;
+};
+
+/**
+ * CaptureResult:
+ *
+ * Identical to @3.2::CaptureResult, except that it contains a list of
+ * physical camera metadata.
+ *
+ * Physical camera metadata needs to be generated if and only if a
+ * request is pending on a stream from that physical camera. For example,
+ * if the processCaptureRequest call doesn't request on physical camera
+ * streams, the physicalCameraMetadata field of the CaptureResult being returned
+ * should be an 0-size vector. If the processCaptureRequest call requests on
+ * streams from one of the physical camera, the physicalCameraMetadata field
+ * should contain one metadata describing the capture from that physical camera.
+ *
+ * For a CaptureResult that contains physical camera metadata, its
+ * partialResult field must be android.request.partialResultCount. In other
+ * words, the physicalCameraMetadata must only be contained in a final capture
+ * result.
+ */
+struct CaptureResult {
+    /**
+     * The definition of CaptureResult from the prior version.
+     */
+    @3.2::CaptureResult v3_2;
+
+    /**
+     * The physical metadata for logical multi-camera.
+     */
+    vec<PhysicalCameraMetadata> physicalCameraMetadata;
+};
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/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, {});
 }