Merge changes from topic 'gralloc-vts'

* changes:
  graphics: add gralloc tests to VTS
  graphics: add basic target-side tests for IMapper
diff --git a/audio/2.0/IStream.hal b/audio/2.0/IStream.hal
index 5c88a69..8de7851 100644
--- a/audio/2.0/IStream.hal
+++ b/audio/2.0/IStream.hal
@@ -279,4 +279,16 @@
      */
     getMmapPosition()
             generates (Result retval, MmapPosition position);
+
+    /*
+     * Called by the framework to deinitialize the stream and free up
+     * all the currently allocated resources. It is recommended to close
+     * the stream on the client side as soon as it is becomes unused.
+     *
+     * @return retval OK in case the success.
+     *                NOT_SUPPORTED if called on IStream instead of input or
+     *                              output stream interface.
+     *                INVALID_STATE if the stream was already closed.
+     */
+    close() generates (Result retval);
 };
diff --git a/audio/2.0/IStreamIn.hal b/audio/2.0/IStreamIn.hal
index 6cf7425..9a96f71 100644
--- a/audio/2.0/IStreamIn.hal
+++ b/audio/2.0/IStreamIn.hal
@@ -41,16 +41,45 @@
     setGain(float gain) generates (Result retval);
 
     /*
-     * Read audio buffer in from driver. If at least one frame was read prior to
-     * the error, 'read' must return that byte count and then return an error
-     * in the subsequent call.
+     * Data structure passed back to the client via status message queue
+     * of 'read' operation.
      *
-     * @param size maximum amount of bytes to read.
-     * @return retval operation completion status.
-     * @return data audio data.
+     * Possible values of 'retval' field:
+     *  - OK, read operation was successful;
+     *  - INVALID_ARGUMENTS, stream was not configured properly;
+     *  - INVALID_STATE, stream is in a state that doesn't allow reads.
      */
-    // TODO(mnaganov): Replace with FMQ version.
-    read(uint64_t size) generates (Result retval, vec<uint8_t> data);
+    struct ReadStatus {
+        Result retval;
+        uint64_t read;
+    };
+
+    /*
+     * Set up required transports for receiving audio buffers from the driver.
+     *
+     * The transport consists of two message queues: one is used for passing
+     * audio data from the driver to the client, another is used for reporting
+     * read operation status (amount of bytes actually read or error code),
+     * see ReadStatus structure definition.
+     *
+     * @param frameSize the size of a single frame, in bytes.
+     * @param framesCount the number of frames in a buffer.
+     * @param threadPriority priority of the thread that performs reads.
+     * @return retval OK if both message queues were created successfully.
+     *                INVALID_STATE if the method was already called.
+     *                INVALID_ARGUMENTS if there was a problem setting up
+     *                                  the queues.
+     * @return dataMQ a message queue used for passing audio data in the format
+     *                specified at the stream opening.
+     * @return statusMQ a message queue used for passing status from the driver
+     *                  using ReadStatus structures.
+     */
+    prepareForReading(
+            uint32_t frameSize, uint32_t framesCount,
+            ThreadPriority threadPriority)
+    generates (
+            Result retval,
+            fmq_sync<uint8_t> dataMQ, fmq_sync<ReadStatus> statusMQ);
 
     /*
      * Return the amount of input frames lost in the audio driver since the last
diff --git a/audio/2.0/IStreamOut.hal b/audio/2.0/IStreamOut.hal
index 4ba3b2f..155e329 100644
--- a/audio/2.0/IStreamOut.hal
+++ b/audio/2.0/IStreamOut.hal
@@ -44,25 +44,48 @@
     setVolume(float left, float right) generates (Result retval);
 
     /*
-     * Write audio buffer to driver. On success, sets 'retval' to 'OK', and
-     * returns number of bytes written. If at least one frame was written
-     * successfully prior to the error, it is suggested that the driver return
-     * that successful (short) byte count and then return an error in the
-     * subsequent call.
+     * Data structure passed back to the client via status message queue
+     * of 'write' operation.
      *
-     * If 'setCallback' has previously been called to enable non-blocking mode
-     * then 'write' is not allowed to block. It must write only the number of
-     * bytes that currently fit in the driver/hardware buffer and then return
-     * this byte count. If this is less than the requested write size the
-     * callback function must be called when more space is available in the
-     * driver/hardware buffer.
-     *
-     * @param data audio data.
-     * @return retval operation completion status.
-     * @return written number of bytes written.
+     * Possible values of 'retval' field:
+     *  - OK, write operation was successful;
+     *  - INVALID_ARGUMENTS, stream was not configured properly;
+     *  - INVALID_STATE, stream is in a state that doesn't allow writes.
      */
-    // TODO(mnaganov): Replace with FMQ version.
-    write(vec<uint8_t> data) generates (Result retval, uint64_t written);
+    struct WriteStatus {
+        Result retval;
+        uint64_t written;
+        uint64_t frames;    // presentation position
+        TimeSpec timeStamp; // presentation position
+    };
+
+    /*
+     * Set up required transports for passing audio buffers to the driver.
+     *
+     * The transport consists of two message queues: one is used for passing
+     * audio data from the client to the driver, another is used for reporting
+     * write operation status (amount of bytes actually written or error code),
+     * and the presentation position immediately after the write, see
+     * WriteStatus structure definition.
+     *
+     * @param frameSize the size of a single frame, in bytes.
+     * @param framesCount the number of frames in a buffer.
+     * @param threadPriority priority of the thread that performs writes.
+     * @return retval OK if both message queues were created successfully.
+     *                INVALID_STATE if the method was already called.
+     *                INVALID_ARGUMENTS if there was a problem setting up
+     *                                  the queues.
+     * @return dataMQ a message queue used for passing audio data in the format
+     *                specified at the stream opening.
+     * @return statusMQ a message queue used for passing status from the driver
+     *                  using WriteStatus structures.
+     */
+    prepareForWriting(
+            uint32_t frameSize, uint32_t framesCount,
+            ThreadPriority threadPriority)
+    generates (
+            Result retval,
+            fmq_sync<uint8_t> dataMQ, fmq_sync<WriteStatus> statusMQ);
 
     /*
      * Return the number of audio frames written by the audio DSP to DAC since
diff --git a/audio/2.0/default/Android.mk b/audio/2.0/default/Android.mk
index c3cfd69..eeea92c 100644
--- a/audio/2.0/default/Android.mk
+++ b/audio/2.0/default/Android.mk
@@ -30,13 +30,16 @@
     StreamOut.cpp \
 
 LOCAL_SHARED_LIBRARIES := \
+    libbase \
+    libcutils \
+    libfmq \
+    libhardware \
     libhidlbase \
     libhidltransport \
     libhwbinder \
-    libcutils \
-    libutils \
-    libhardware \
     liblog \
+    libmediautils \
+    libutils \
     android.hardware.audio@2.0 \
     android.hardware.audio.common@2.0 \
     android.hardware.audio.common@2.0-util \
diff --git a/audio/2.0/default/Stream.cpp b/audio/2.0/default/Stream.cpp
index f214eed..62b34a3 100644
--- a/audio/2.0/default/Stream.cpp
+++ b/audio/2.0/default/Stream.cpp
@@ -253,6 +253,10 @@
     return Void();
 }
 
+Return<Result> Stream::close()  {
+    return Result::NOT_SUPPORTED;
+}
+
 } // namespace implementation
 }  // namespace V2_0
 }  // namespace audio
diff --git a/audio/2.0/default/Stream.h b/audio/2.0/default/Stream.h
index 819bbf7..0bbd803 100644
--- a/audio/2.0/default/Stream.h
+++ b/audio/2.0/default/Stream.h
@@ -76,6 +76,7 @@
     Return<Result> stop() override;
     Return<void> createMmapBuffer(int32_t minSizeFrames, createMmapBuffer_cb _hidl_cb) override;
     Return<void> getMmapPosition(getMmapPosition_cb _hidl_cb) override;
+    Return<Result> close()  override;
 
     // Utility methods for extending interfaces.
     static Result analyzeStatus(const char* funcName, int status, int ignoreError = OK);
diff --git a/audio/2.0/default/StreamIn.cpp b/audio/2.0/default/StreamIn.cpp
index 1441e74..51c2cc7 100644
--- a/audio/2.0/default/StreamIn.cpp
+++ b/audio/2.0/default/StreamIn.cpp
@@ -15,26 +15,112 @@
  */
 
 #define LOG_TAG "StreamInHAL"
+//#define LOG_NDEBUG 0
 
-#include <hardware/audio.h>
 #include <android/log.h>
+#include <hardware/audio.h>
+#include <mediautils/SchedulingPolicyService.h>
 
 #include "StreamIn.h"
 
+using ::android::hardware::audio::V2_0::MessageQueueFlagBits;
+
 namespace android {
 namespace hardware {
 namespace audio {
 namespace V2_0 {
 namespace implementation {
 
+namespace {
+
+class ReadThread : public Thread {
+  public:
+    // ReadThread's lifespan never exceeds StreamIn's lifespan.
+    ReadThread(std::atomic<bool>* stop,
+            audio_stream_in_t* stream,
+            StreamIn::DataMQ* dataMQ,
+            StreamIn::StatusMQ* statusMQ,
+            EventFlag* efGroup,
+            ThreadPriority threadPriority)
+            : Thread(false /*canCallJava*/),
+              mStop(stop),
+              mStream(stream),
+              mDataMQ(dataMQ),
+              mStatusMQ(statusMQ),
+              mEfGroup(efGroup),
+              mThreadPriority(threadPriority),
+              mBuffer(new uint8_t[dataMQ->getQuantumCount()]) {
+    }
+    virtual ~ReadThread() {}
+
+    status_t readyToRun() override;
+
+  private:
+    std::atomic<bool>* mStop;
+    audio_stream_in_t* mStream;
+    StreamIn::DataMQ* mDataMQ;
+    StreamIn::StatusMQ* mStatusMQ;
+    EventFlag* mEfGroup;
+    ThreadPriority mThreadPriority;
+    std::unique_ptr<uint8_t[]> mBuffer;
+
+    bool threadLoop() override;
+};
+
+status_t ReadThread::readyToRun() {
+    if (mThreadPriority != ThreadPriority::NORMAL) {
+        int err = requestPriority(
+                getpid(), getTid(), static_cast<int>(mThreadPriority), true /*asynchronous*/);
+        ALOGW_IF(err, "failed to set priority %d for pid %d tid %d; error %d",
+                static_cast<int>(mThreadPriority), getpid(), getTid(), err);
+    }
+    return OK;
+}
+
+bool ReadThread::threadLoop() {
+    // This implementation doesn't return control back to the Thread until it decides to stop,
+    // as the Thread uses mutexes, and this can lead to priority inversion.
+    while(!std::atomic_load_explicit(mStop, std::memory_order_acquire)) {
+        // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
+        uint32_t efState = 0;
+        mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL), &efState, NS_PER_SEC);
+        if (!(efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL))) {
+            continue;  // Nothing to do.
+        }
+
+        const size_t availToWrite = mDataMQ->availableToWrite();
+        ssize_t readResult = mStream->read(mStream, &mBuffer[0], availToWrite);
+        Result retval = Result::OK;
+        uint64_t read = 0;
+        if (readResult >= 0) {
+            read = readResult;
+            if (!mDataMQ->write(&mBuffer[0], readResult)) {
+                ALOGW("data message queue write failed");
+            }
+        } else {
+            retval = Stream::analyzeStatus("read", readResult);
+        }
+        IStreamIn::ReadStatus status = { retval, read };
+        if (!mStatusMQ->write(&status)) {
+            ALOGW("status message queue write failed");
+        }
+        mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
+    }
+
+    return false;
+}
+
+}  // namespace
+
 StreamIn::StreamIn(audio_hw_device_t* device, audio_stream_in_t* stream)
-        : mDevice(device), mStream(stream),
+        : mIsClosed(false), mDevice(device), mStream(stream),
           mStreamCommon(new Stream(&stream->common)),
-          mStreamMmap(new StreamMmap<audio_stream_in_t>(stream)) {
+          mStreamMmap(new StreamMmap<audio_stream_in_t>(stream)),
+          mEfGroup(nullptr), mStopReadThread(false) {
 }
 
 StreamIn::~StreamIn() {
-    mDevice->close_input_stream(mDevice, mStream);
+    close();
     mStream = nullptr;
     mDevice = nullptr;
 }
@@ -149,6 +235,22 @@
     return mStreamMmap->getMmapPosition(_hidl_cb);
 }
 
+Return<Result> StreamIn::close()  {
+    if (mIsClosed) return Result::INVALID_STATE;
+    mIsClosed = true;
+    if (mReadThread.get()) {
+        mStopReadThread.store(true, std::memory_order_release);
+        status_t status = mReadThread->requestExitAndWait();
+        ALOGE_IF(status, "read thread exit error: %s", strerror(-status));
+    }
+    if (mEfGroup) {
+        status_t status = EventFlag::deleteEventFlag(&mEfGroup);
+        ALOGE_IF(status, "read MQ event flag deletion error: %s", strerror(-status));
+    }
+    mDevice->close_input_stream(mDevice, mStream);
+    return Result::OK;
+}
+
 // Methods from ::android::hardware::audio::V2_0::IStreamIn follow.
 Return<void> StreamIn::getAudioSource(getAudioSource_cb _hidl_cb)  {
     int halSource;
@@ -165,19 +267,55 @@
     return Stream::analyzeStatus("set_gain", mStream->set_gain(mStream, gain));
 }
 
-Return<void> StreamIn::read(uint64_t size, read_cb _hidl_cb)  {
-    // TODO(mnaganov): Replace with FMQ version.
-    hidl_vec<uint8_t> data;
-    data.resize(size);
-    Result retval(Result::OK);
-    ssize_t readResult = mStream->read(mStream, &data[0], data.size());
-    if (readResult >= 0 && static_cast<size_t>(readResult) != data.size()) {
-        data.resize(readResult);
-    } else if (readResult < 0) {
-        data.resize(0);
-        retval = Stream::analyzeStatus("read", readResult);
+Return<void> StreamIn::prepareForReading(
+        uint32_t frameSize, uint32_t framesCount, ThreadPriority threadPriority,
+        prepareForReading_cb _hidl_cb)  {
+    status_t status;
+    // Create message queues.
+    if (mDataMQ) {
+        ALOGE("the client attempts to call prepareForReading twice");
+        _hidl_cb(Result::INVALID_STATE,
+                MQDescriptorSync<uint8_t>(), MQDescriptorSync<ReadStatus>());
+        return Void();
     }
-    _hidl_cb(retval, data);
+    std::unique_ptr<DataMQ> tempDataMQ(
+            new DataMQ(frameSize * framesCount, true /* EventFlag */));
+    std::unique_ptr<StatusMQ> tempStatusMQ(new StatusMQ(1));
+    if (!tempDataMQ->isValid() || !tempStatusMQ->isValid()) {
+        ALOGE_IF(!tempDataMQ->isValid(), "data MQ is invalid");
+        ALOGE_IF(!tempStatusMQ->isValid(), "status MQ is invalid");
+        _hidl_cb(Result::INVALID_ARGUMENTS,
+                MQDescriptorSync<uint8_t>(), MQDescriptorSync<ReadStatus>());
+        return Void();
+    }
+    // TODO: Remove event flag management once blocking MQ is implemented. b/33815422
+    status = EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
+    if (status != OK || !mEfGroup) {
+        ALOGE("failed creating event flag for data MQ: %s", strerror(-status));
+        _hidl_cb(Result::INVALID_ARGUMENTS,
+                MQDescriptorSync<uint8_t>(), MQDescriptorSync<ReadStatus>());
+        return Void();
+    }
+
+    // Create and launch the thread.
+    mReadThread = new ReadThread(
+            &mStopReadThread,
+            mStream,
+            tempDataMQ.get(),
+            tempStatusMQ.get(),
+            mEfGroup,
+            threadPriority);
+    status = mReadThread->run("reader", PRIORITY_URGENT_AUDIO);
+    if (status != OK) {
+        ALOGW("failed to start reader thread: %s", strerror(-status));
+        _hidl_cb(Result::INVALID_ARGUMENTS,
+                MQDescriptorSync<uint8_t>(), MQDescriptorSync<ReadStatus>());
+        return Void();
+    }
+
+    mDataMQ = std::move(tempDataMQ);
+    mStatusMQ = std::move(tempStatusMQ);
+    _hidl_cb(Result::OK, *mDataMQ->getDesc(), *mStatusMQ->getDesc());
     return Void();
 }
 
diff --git a/audio/2.0/default/StreamIn.h b/audio/2.0/default/StreamIn.h
index 65e94bb..fc813d9 100644
--- a/audio/2.0/default/StreamIn.h
+++ b/audio/2.0/default/StreamIn.h
@@ -17,10 +17,15 @@
 #ifndef ANDROID_HARDWARE_AUDIO_V2_0_STREAMIN_H
 #define ANDROID_HARDWARE_AUDIO_V2_0_STREAMIN_H
 
-#include <android/hardware/audio/2.0/IStreamIn.h>
-#include <hidl/Status.h>
+#include <atomic>
+#include <memory>
 
+#include <android/hardware/audio/2.0/IStreamIn.h>
 #include <hidl/MQDescriptor.h>
+#include <fmq/EventFlag.h>
+#include <fmq/MessageQueue.h>
+#include <hidl/Status.h>
+#include <utils/Thread.h>
 
 #include "Stream.h"
 
@@ -39,6 +44,7 @@
 using ::android::hardware::audio::V2_0::IStreamIn;
 using ::android::hardware::audio::V2_0::ParameterValue;
 using ::android::hardware::audio::V2_0::Result;
+using ::android::hardware::audio::V2_0::ThreadPriority;
 using ::android::hardware::Return;
 using ::android::hardware::Void;
 using ::android::hardware::hidl_vec;
@@ -46,6 +52,9 @@
 using ::android::sp;
 
 struct StreamIn : public IStreamIn {
+    typedef MessageQueue<uint8_t, kSynchronizedReadWrite> DataMQ;
+    typedef MessageQueue<ReadStatus, kSynchronizedReadWrite> StatusMQ;
+
     StreamIn(audio_hw_device_t* device, audio_stream_in_t* stream);
 
     // Methods from ::android::hardware::audio::V2_0::IStream follow.
@@ -73,11 +82,14 @@
             const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb)  override;
     Return<Result> setParameters(const hidl_vec<ParameterValue>& parameters)  override;
     Return<void> debugDump(const hidl_handle& fd)  override;
+    Return<Result> close()  override;
 
     // Methods from ::android::hardware::audio::V2_0::IStreamIn follow.
     Return<void> getAudioSource(getAudioSource_cb _hidl_cb)  override;
     Return<Result> setGain(float gain)  override;
-    Return<void> read(uint64_t size, read_cb _hidl_cb)  override;
+    Return<void> prepareForReading(
+            uint32_t frameSize, uint32_t framesCount, ThreadPriority threadPriority,
+            prepareForReading_cb _hidl_cb)  override;
     Return<uint32_t> getInputFramesLost()  override;
     Return<void> getCapturePosition(getCapturePosition_cb _hidl_cb)  override;
     Return<Result> start() override;
@@ -86,11 +98,16 @@
     Return<void> getMmapPosition(getMmapPosition_cb _hidl_cb) override;
 
   private:
+    bool mIsClosed;
     audio_hw_device_t *mDevice;
     audio_stream_in_t *mStream;
     sp<Stream> mStreamCommon;
     sp<StreamMmap<audio_stream_in_t>> mStreamMmap;
-
+    std::unique_ptr<DataMQ> mDataMQ;
+    std::unique_ptr<StatusMQ> mStatusMQ;
+    EventFlag* mEfGroup;
+    std::atomic<bool> mStopReadThread;
+    sp<Thread> mReadThread;
 
     virtual ~StreamIn();
 };
diff --git a/audio/2.0/default/StreamOut.cpp b/audio/2.0/default/StreamOut.cpp
index 3d20d11..4bb2274 100644
--- a/audio/2.0/default/StreamOut.cpp
+++ b/audio/2.0/default/StreamOut.cpp
@@ -17,8 +17,9 @@
 #define LOG_TAG "StreamOutHAL"
 //#define LOG_NDEBUG 0
 
-#include <hardware/audio.h>
 #include <android/log.h>
+#include <hardware/audio.h>
+#include <mediautils/SchedulingPolicyService.h>
 
 #include "StreamOut.h"
 
@@ -28,15 +29,103 @@
 namespace V2_0 {
 namespace implementation {
 
+namespace {
+
+class WriteThread : public Thread {
+  public:
+    // WriteThread's lifespan never exceeds StreamOut's lifespan.
+    WriteThread(std::atomic<bool>* stop,
+            audio_stream_out_t* stream,
+            StreamOut::DataMQ* dataMQ,
+            StreamOut::StatusMQ* statusMQ,
+            EventFlag* efGroup,
+            ThreadPriority threadPriority)
+            : Thread(false /*canCallJava*/),
+              mStop(stop),
+              mStream(stream),
+              mDataMQ(dataMQ),
+              mStatusMQ(statusMQ),
+              mEfGroup(efGroup),
+              mThreadPriority(threadPriority),
+              mBuffer(new uint8_t[dataMQ->getQuantumCount()]) {
+    }
+    virtual ~WriteThread() {}
+
+    status_t readyToRun() override;
+
+  private:
+    std::atomic<bool>* mStop;
+    audio_stream_out_t* mStream;
+    StreamOut::DataMQ* mDataMQ;
+    StreamOut::StatusMQ* mStatusMQ;
+    EventFlag* mEfGroup;
+    ThreadPriority mThreadPriority;
+    std::unique_ptr<uint8_t[]> mBuffer;
+
+    bool threadLoop() override;
+};
+
+status_t WriteThread::readyToRun() {
+    if (mThreadPriority != ThreadPriority::NORMAL) {
+        int err = requestPriority(
+                getpid(), getTid(), static_cast<int>(mThreadPriority), true /*asynchronous*/);
+        ALOGW_IF(err, "failed to set priority %d for pid %d tid %d; error %d",
+                static_cast<int>(mThreadPriority), getpid(), getTid(), err);
+    }
+    return OK;
+}
+
+bool WriteThread::threadLoop() {
+    // This implementation doesn't return control back to the Thread until it decides to stop,
+    // as the Thread uses mutexes, and this can lead to priority inversion.
+    while(!std::atomic_load_explicit(mStop, std::memory_order_acquire)) {
+        // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
+        uint32_t efState = 0;
+        mEfGroup->wait(
+                static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), &efState, NS_PER_SEC);
+        if (!(efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY))) {
+            continue;  // Nothing to do.
+        }
+
+        const size_t availToRead = mDataMQ->availableToRead();
+        Result retval = Result::OK;
+        uint64_t written = 0;
+        if (mDataMQ->read(&mBuffer[0], availToRead)) {
+            ssize_t writeResult = mStream->write(mStream, &mBuffer[0], availToRead);
+            if (writeResult >= 0) {
+                written = writeResult;
+            } else {
+                retval = Stream::analyzeStatus("write", writeResult);
+            }
+        }
+        uint64_t frames = 0;
+        struct timespec halTimeStamp = { 0, 0 };
+        if (retval == Result::OK && mStream->get_presentation_position != NULL) {
+            mStream->get_presentation_position(mStream, &frames, &halTimeStamp);
+        }
+        IStreamOut::WriteStatus status = { retval, written, frames,
+                                           { static_cast<uint64_t>(halTimeStamp.tv_sec),
+                                             static_cast<uint64_t>(halTimeStamp.tv_nsec) } };
+        if (!mStatusMQ->write(&status)) {
+            ALOGW("status message queue write failed");
+        }
+        mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
+    }
+
+    return false;
+}
+
+}  // namespace
+
 StreamOut::StreamOut(audio_hw_device_t* device, audio_stream_out_t* stream)
-        : mDevice(device), mStream(stream),
+        : mIsClosed(false), mDevice(device), mStream(stream),
           mStreamCommon(new Stream(&stream->common)),
-          mStreamMmap(new StreamMmap<audio_stream_out_t>(stream)) {
+          mStreamMmap(new StreamMmap<audio_stream_out_t>(stream)),
+          mEfGroup(nullptr), mStopWriteThread(false) {
 }
 
 StreamOut::~StreamOut() {
-    mCallback.clear();
-    mDevice->close_output_stream(mDevice, mStream);
+    close();
     mStream = nullptr;
     mDevice = nullptr;
 }
@@ -135,6 +224,23 @@
     return mStreamCommon->debugDump(fd);
 }
 
+Return<Result> StreamOut::close()  {
+    if (mIsClosed) return Result::INVALID_STATE;
+    mIsClosed = true;
+    if (mWriteThread.get()) {
+        mStopWriteThread.store(true, std::memory_order_release);
+        status_t status = mWriteThread->requestExitAndWait();
+        ALOGE_IF(status, "write thread exit error: %s", strerror(-status));
+    }
+    if (mEfGroup) {
+        status_t status = EventFlag::deleteEventFlag(&mEfGroup);
+        ALOGE_IF(status, "write MQ event flag deletion error: %s", strerror(-status));
+    }
+    mCallback.clear();
+    mDevice->close_output_stream(mDevice, mStream);
+    return Result::OK;
+}
+
 // Methods from ::android::hardware::audio::V2_0::IStreamOut follow.
 Return<uint32_t> StreamOut::getLatency()  {
     return mStream->get_latency(mStream);
@@ -149,18 +255,55 @@
     return retval;
 }
 
-Return<void> StreamOut::write(const hidl_vec<uint8_t>& data, write_cb _hidl_cb)  {
-    // TODO(mnaganov): Replace with FMQ version.
-    Result retval(Result::OK);
-    uint64_t written = 0;
-    ssize_t writeResult = mStream->write(mStream, &data[0], data.size());
-    if (writeResult >= 0) {
-        written = writeResult;
-    } else {
-        retval = Stream::analyzeStatus("write", writeResult);
-        written = 0;
+Return<void> StreamOut::prepareForWriting(
+        uint32_t frameSize, uint32_t framesCount, ThreadPriority threadPriority,
+        prepareForWriting_cb _hidl_cb)  {
+    status_t status;
+    // Create message queues.
+    if (mDataMQ) {
+        ALOGE("the client attempts to call prepareForWriting twice");
+        _hidl_cb(Result::INVALID_STATE,
+                MQDescriptorSync<uint8_t>(), MQDescriptorSync<WriteStatus>());
+        return Void();
     }
-    _hidl_cb(retval, written);
+    std::unique_ptr<DataMQ> tempDataMQ(
+            new DataMQ(frameSize * framesCount, true /* EventFlag */));
+    std::unique_ptr<StatusMQ> tempStatusMQ(new StatusMQ(1));
+    if (!tempDataMQ->isValid() || !tempStatusMQ->isValid()) {
+        ALOGE_IF(!tempDataMQ->isValid(), "data MQ is invalid");
+        ALOGE_IF(!tempStatusMQ->isValid(), "status MQ is invalid");
+        _hidl_cb(Result::INVALID_ARGUMENTS,
+                MQDescriptorSync<uint8_t>(), MQDescriptorSync<WriteStatus>());
+        return Void();
+    }
+    // TODO: Remove event flag management once blocking MQ is implemented. b/33815422
+    status = EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
+    if (status != OK || !mEfGroup) {
+        ALOGE("failed creating event flag for data MQ: %s", strerror(-status));
+        _hidl_cb(Result::INVALID_ARGUMENTS,
+                MQDescriptorSync<uint8_t>(), MQDescriptorSync<WriteStatus>());
+        return Void();
+    }
+
+    // Create and launch the thread.
+    mWriteThread = new WriteThread(
+            &mStopWriteThread,
+            mStream,
+            tempDataMQ.get(),
+            tempStatusMQ.get(),
+            mEfGroup,
+            threadPriority);
+    status = mWriteThread->run("writer", PRIORITY_URGENT_AUDIO);
+    if (status != OK) {
+        ALOGW("failed to start writer thread: %s", strerror(-status));
+        _hidl_cb(Result::INVALID_ARGUMENTS,
+                MQDescriptorSync<uint8_t>(), MQDescriptorSync<WriteStatus>());
+        return Void();
+    }
+
+    mDataMQ = std::move(tempDataMQ);
+    mStatusMQ = std::move(tempStatusMQ);
+    _hidl_cb(Result::OK, *mDataMQ->getDesc(), *mStatusMQ->getDesc());
     return Void();
 }
 
diff --git a/audio/2.0/default/StreamOut.h b/audio/2.0/default/StreamOut.h
index 9b7f9f8..83f4447 100644
--- a/audio/2.0/default/StreamOut.h
+++ b/audio/2.0/default/StreamOut.h
@@ -17,10 +17,15 @@
 #ifndef ANDROID_HARDWARE_AUDIO_V2_0_STREAMOUT_H
 #define ANDROID_HARDWARE_AUDIO_V2_0_STREAMOUT_H
 
-#include <android/hardware/audio/2.0/IStreamOut.h>
-#include <hidl/Status.h>
+#include <atomic>
+#include <memory>
 
+#include <android/hardware/audio/2.0/IStreamOut.h>
 #include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <fmq/EventFlag.h>
+#include <fmq/MessageQueue.h>
+#include <utils/Thread.h>
 
 #include "Stream.h"
 
@@ -40,6 +45,7 @@
 using ::android::hardware::audio::V2_0::IStreamOutCallback;
 using ::android::hardware::audio::V2_0::ParameterValue;
 using ::android::hardware::audio::V2_0::Result;
+using ::android::hardware::audio::V2_0::ThreadPriority;
 using ::android::hardware::audio::V2_0::TimeSpec;
 using ::android::hardware::Return;
 using ::android::hardware::Void;
@@ -48,6 +54,9 @@
 using ::android::sp;
 
 struct StreamOut : public IStreamOut {
+    typedef MessageQueue<uint8_t, kSynchronizedReadWrite> DataMQ;
+    typedef MessageQueue<WriteStatus, kSynchronizedReadWrite> StatusMQ;
+
     StreamOut(audio_hw_device_t* device, audio_stream_out_t* stream);
 
     // Methods from ::android::hardware::audio::V2_0::IStream follow.
@@ -75,11 +84,14 @@
             const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb)  override;
     Return<Result> setParameters(const hidl_vec<ParameterValue>& parameters)  override;
     Return<void> debugDump(const hidl_handle& fd)  override;
+    Return<Result> close()  override;
 
     // Methods from ::android::hardware::audio::V2_0::IStreamOut follow.
     Return<uint32_t> getLatency()  override;
     Return<Result> setVolume(float left, float right)  override;
-    Return<void> write(const hidl_vec<uint8_t>& data, write_cb _hidl_cb)  override;
+    Return<void> prepareForWriting(
+            uint32_t frameSize, uint32_t framesCount, ThreadPriority threadPriority,
+            prepareForWriting_cb _hidl_cb)  override;
     Return<void> getRenderPosition(getRenderPosition_cb _hidl_cb)  override;
     Return<void> getNextWriteTimestamp(getNextWriteTimestamp_cb _hidl_cb)  override;
     Return<Result> setCallback(const sp<IStreamOutCallback>& callback)  override;
@@ -97,11 +109,17 @@
     Return<void> getMmapPosition(getMmapPosition_cb _hidl_cb) override;
 
   private:
+    bool mIsClosed;
     audio_hw_device_t *mDevice;
     audio_stream_out_t *mStream;
     sp<Stream> mStreamCommon;
     sp<StreamMmap<audio_stream_out_t>> mStreamMmap;
     sp<IStreamOutCallback> mCallback;
+    std::unique_ptr<DataMQ> mDataMQ;
+    std::unique_ptr<StatusMQ> mStatusMQ;
+    EventFlag* mEfGroup;
+    std::atomic<bool> mStopWriteThread;
+    sp<Thread> mWriteThread;
 
     virtual ~StreamOut();
 
diff --git a/audio/2.0/types.hal b/audio/2.0/types.hal
index 37c39e4..8fc4314 100644
--- a/audio/2.0/types.hal
+++ b/audio/2.0/types.hal
@@ -89,3 +89,21 @@
     int64_t  timeNanoseconds; // time stamp in ns, CLOCK_MONOTONIC
     int32_t  positionFrames;  // increasing 32 bit frame count reset when IStream.stop() is called
 };
+
+/*
+ * The message queue flags used to synchronize reads and writes from
+ * message queues used by StreamIn and StreamOut.
+ */
+enum MessageQueueFlagBits : uint32_t {
+    NOT_EMPTY = 1 << 0,
+    NOT_FULL = 1 << 1
+};
+
+/*
+ * The priority of threads executing reads and writes of audio data.
+ */
+enum ThreadPriority : int32_t {
+    NORMAL = 0,
+    FAST_CAPTURE = 3,
+    FAST_MIXER = 3
+};
diff --git a/audio/effect/2.0/vts/functional/audio_effect_hidl_hal_test.cpp b/audio/effect/2.0/vts/functional/audio_effect_hidl_hal_test.cpp
index 1e0ab32..9b7d0cf 100644
--- a/audio/effect/2.0/vts/functional/audio_effect_hidl_hal_test.cpp
+++ b/audio/effect/2.0/vts/functional/audio_effect_hidl_hal_test.cpp
@@ -65,7 +65,7 @@
         retval = r;
         effectCount = result.size();
       });
-  EXPECT_EQ(ret.getStatus().exceptionCode(), Status::EX_NONE);
+  EXPECT_TRUE(ret.isOk());
   EXPECT_EQ(retval, Result::OK);
   EXPECT_GT(effectCount, 0u);
 }
@@ -80,7 +80,7 @@
           effectUuid = result[0].uuid;
         }
       });
-  ASSERT_EQ(ret.getStatus().exceptionCode(), Status::EX_NONE);
+  ASSERT_TRUE(ret.isOk());
   ASSERT_TRUE(gotEffect);
   Result retval = Result::NOT_INITIALIZED;
   sp<IEffect> effect;
@@ -92,7 +92,7 @@
           effect = result;
         }
       });
-  EXPECT_EQ(ret.getStatus().exceptionCode(), Status::EX_NONE);
+  EXPECT_TRUE(ret.isOk());
   EXPECT_EQ(retval, Result::OK);
   EXPECT_NE(effect, nullptr);
 }
@@ -105,7 +105,7 @@
           allDescriptors = result;
         }
       });
-  ASSERT_EQ(ret.getStatus().exceptionCode(), Status::EX_NONE);
+  ASSERT_TRUE(ret.isOk());
   ASSERT_GT(allDescriptors.size(), 0u);
   for (size_t i = 0; i < allDescriptors.size(); ++i) {
     ret = effectsFactory->getDescriptor(
@@ -114,7 +114,7 @@
           EXPECT_EQ(result, allDescriptors[i]);
         });
   }
-  EXPECT_EQ(ret.getStatus().exceptionCode(), Status::EX_NONE);
+  EXPECT_TRUE(ret.isOk());
 }
 
 int main(int argc, char** argv) {
diff --git a/audio/effect/2.0/vts/functional/vts/testcases/hal/audio/effect/hidl/target/AndroidTest.xml b/audio/effect/2.0/vts/functional/vts/testcases/hal/audio/effect/hidl/target/AndroidTest.xml
index f0af67a..60a2cd0 100644
--- a/audio/effect/2.0/vts/functional/vts/testcases/hal/audio/effect/hidl/target/AndroidTest.xml
+++ b/audio/effect/2.0/vts/functional/vts/testcases/hal/audio/effect/hidl/target/AndroidTest.xml
@@ -24,6 +24,7 @@
             _32bit::DATA/nativetest/audio_effect_hidl_hal_test/audio_effect_hidl_hal_test,
             _64bit::DATA/nativetest64/audio_effect_hidl_hal_test/audio_effect_hidl_hal_test,
             "/>
+        <option name="test-config-path" value="vts/testcases/hal/audio/effect/hidl/target/HalAudioEffectHidlTargetBasicTest.config" />
         <option name="binary-test-type" value="gtest" />
         <option name="test-timeout" value="1m" />
     </test>
diff --git a/audio/effect/2.0/vts/functional/vts/testcases/hal/audio/effect/hidl/target/HalAudioEffectHidlTargetBasicTest.config b/audio/effect/2.0/vts/functional/vts/testcases/hal/audio/effect/hidl/target/HalAudioEffectHidlTargetBasicTest.config
new file mode 100644
index 0000000..495fda9
--- /dev/null
+++ b/audio/effect/2.0/vts/functional/vts/testcases/hal/audio/effect/hidl/target/HalAudioEffectHidlTargetBasicTest.config
@@ -0,0 +1,11 @@
+{
+    "use_gae_db": true,
+    "coverage": true,
+    "modules": [{
+                    "module_name": "system/lib64/hw/android.hardware.audio.effect@2.0-impl",
+                    "git_project": {
+                        "name": "platform/hardware/interfaces",
+                        "path": "hardware/interfaces"
+                    }
+                }]
+}
diff --git a/boot/1.0/vts/functional/boot_hidl_hal_test.cpp b/boot/1.0/vts/functional/boot_hidl_hal_test.cpp
index 7b002b9..cdca7e2 100644
--- a/boot/1.0/vts/functional/boot_hidl_hal_test.cpp
+++ b/boot/1.0/vts/functional/boot_hidl_hal_test.cpp
@@ -75,7 +75,7 @@
 TEST_F(BootHidlTest, MarkBootSuccessful) {
   CommandResult cr;
   Return<void> result = boot->markBootSuccessful(generate_callback(&cr));
-  ASSERT_TRUE(result.getStatus().isOk());
+  ASSERT_TRUE(result.isOk());
   if (cr.success) {
     Slot curSlot = boot->getCurrentSlot();
     BoolResult ret = boot->isSlotMarkedSuccessful(curSlot);
@@ -88,14 +88,14 @@
   for (Slot s = 0; s < 2; s++) {
     CommandResult cr;
     Return<void> result = boot->setActiveBootSlot(s, generate_callback(&cr));
-    EXPECT_TRUE(result.getStatus().isOk());
+    EXPECT_TRUE(result.isOk());
   }
   {
     CommandResult cr;
     uint32_t slots = boot->getNumberSlots();
     Return<void> result =
         boot->setActiveBootSlot(slots, generate_callback(&cr));
-    ASSERT_TRUE(result.getStatus().isOk());
+    ASSERT_TRUE(result.isOk());
     EXPECT_EQ(false, cr.success);
   }
 }
@@ -108,7 +108,7 @@
     Slot otherSlot = curSlot ? 0 : 1;
     Return<void> result =
         boot->setSlotAsUnbootable(otherSlot, generate_callback(&cr));
-    EXPECT_TRUE(result.getStatus().isOk());
+    EXPECT_TRUE(result.isOk());
     if (cr.success) {
       EXPECT_EQ(BoolResult::FALSE, boot->isSlotBootable(otherSlot));
       boot->setActiveBootSlot(otherSlot, generate_callback(&cr));
@@ -120,7 +120,7 @@
     uint32_t slots = boot->getNumberSlots();
     Return<void> result =
         boot->setSlotAsUnbootable(slots, generate_callback(&cr));
-    EXPECT_TRUE(result.getStatus().isOk());
+    EXPECT_TRUE(result.isOk());
     EXPECT_EQ(false, cr.success);
   }
 }
@@ -150,7 +150,7 @@
   for (Slot i = 0; i < 2; i++) {
     CommandResult cr;
     Return<void> result = boot->getSuffix(i, cb);
-    EXPECT_TRUE(result.getStatus().isOk());
+    EXPECT_TRUE(result.isOk());
     char correctSuffix[3];
     snprintf(correctSuffix, sizeof(correctSuffix), "_%c", 'a' + i);
     ASSERT_EQ(0, strcmp(suffixPtr, correctSuffix));
@@ -158,7 +158,7 @@
   {
     char emptySuffix[] = "";
     Return<void> result = boot->getSuffix(boot->getNumberSlots(), cb);
-    EXPECT_TRUE(result.getStatus().isOk());
+    EXPECT_TRUE(result.isOk());
     ASSERT_EQ(0, strcmp(emptySuffix, suffixPtr));
   }
 }
diff --git a/broadcastradio/1.0/vts/functional/broadcastradio_hidl_hal_test.cpp b/broadcastradio/1.0/vts/functional/broadcastradio_hidl_hal_test.cpp
index 6802c3c..12bbb6b 100644
--- a/broadcastradio/1.0/vts/functional/broadcastradio_hidl_hal_test.cpp
+++ b/broadcastradio/1.0/vts/functional/broadcastradio_hidl_hal_test.cpp
@@ -241,7 +241,7 @@
                         }
                     });
 
-        EXPECT_EQ(Status::EX_NONE, hidlReturn.getStatus().exceptionCode());
+        EXPECT_TRUE(hidlReturn.isOk());
         EXPECT_EQ(Result::OK, halResult);
         EXPECT_EQ(Class::AM_FM, mHalProperties.classId);
         EXPECT_GT(mHalProperties.numTuners, 0u);
@@ -265,7 +265,7 @@
                             mTuner = tuner;
                         }
                     });
-        EXPECT_EQ(Status::EX_NONE, hidlReturn.getStatus().exceptionCode());
+        EXPECT_TRUE(hidlReturn.isOk());
         EXPECT_EQ(Result::OK, halResult);
         EXPECT_EQ(true, waitForCallback(kConfigCallbacktimeoutNs));
     }
@@ -328,7 +328,7 @@
     // test setConfiguration
     mCallbackCalled = false;
     Return<Result> hidlResult = mTuner->setConfiguration(mHalProperties.bands[0]);
-    EXPECT_EQ(Status::EX_NONE, hidlResult.getStatus().exceptionCode());
+    EXPECT_TRUE(hidlResult.isOk());
     EXPECT_EQ(Result::OK, hidlResult);
     EXPECT_EQ(true, waitForCallback(kConfigCallbacktimeoutNs));
     EXPECT_EQ(Result::OK, mResultCallbackData);
@@ -343,7 +343,7 @@
                     halConfig = config;
                 }
             });
-    EXPECT_EQ(Status::EX_NONE, hidlReturn.getStatus().exceptionCode());
+    EXPECT_TRUE(hidlReturn.isOk());
     EXPECT_EQ(Result::OK, halResult);
     EXPECT_EQ(mHalProperties.bands[0].type, halConfig.type);
 }
@@ -362,14 +362,14 @@
     // test scan UP
     mCallbackCalled = false;
     Return<Result> hidlResult = mTuner->scan(Direction::UP, true);
-    EXPECT_EQ(Status::EX_NONE, hidlResult.getStatus().exceptionCode());
+    EXPECT_TRUE(hidlResult.isOk());
     EXPECT_EQ(Result::OK, hidlResult);
     EXPECT_EQ(true, waitForCallback(kTuneCallbacktimeoutNs));
 
     // test scan DOWN
     mCallbackCalled = false;
     hidlResult = mTuner->scan(Direction::DOWN, true);
-    EXPECT_EQ(Status::EX_NONE, hidlResult.getStatus().exceptionCode());
+    EXPECT_TRUE(hidlResult.isOk());
     EXPECT_EQ(Result::OK, hidlResult);
     EXPECT_EQ(true, waitForCallback(kTuneCallbacktimeoutNs));
 }
@@ -388,14 +388,14 @@
     // test step UP
     mCallbackCalled = false;
     Return<Result> hidlResult = mTuner->step(Direction::UP, true);
-    EXPECT_EQ(Status::EX_NONE, hidlResult.getStatus().exceptionCode());
+    EXPECT_TRUE(hidlResult.isOk());
     EXPECT_EQ(Result::OK, hidlResult);
     EXPECT_EQ(true, waitForCallback(kTuneCallbacktimeoutNs));
 
     // test step DOWN
     mCallbackCalled = false;
     hidlResult = mTuner->step(Direction::DOWN, true);
-    EXPECT_EQ(Status::EX_NONE, hidlResult.getStatus().exceptionCode());
+    EXPECT_TRUE(hidlResult.isOk());
     EXPECT_EQ(Result::OK, hidlResult);
     EXPECT_EQ(true, waitForCallback(kTuneCallbacktimeoutNs));
 }
@@ -426,7 +426,7 @@
     mCallbackCalled = false;
     mResultCallbackData = Result::NOT_INITIALIZED;
     Return<Result> hidlResult = mTuner->tune(channel, 0);
-    EXPECT_EQ(Status::EX_NONE, hidlResult.getStatus().exceptionCode());
+    EXPECT_TRUE(hidlResult.isOk());
     EXPECT_EQ(Result::OK, hidlResult);
     EXPECT_EQ(true, waitForCallback(kTuneCallbacktimeoutNs));
 
@@ -440,7 +440,7 @@
                                     halInfo = info;
                                 }
         });
-    EXPECT_EQ(Status::EX_NONE, hidlReturn.getStatus().exceptionCode());
+    EXPECT_TRUE(hidlReturn.isOk());
     EXPECT_EQ(Result::OK, halResult);
     if (mResultCallbackData == Result::OK) {
         EXPECT_EQ(true, halInfo.tuned);
@@ -453,7 +453,7 @@
     // test cancel
     mTuner->tune(lowerLimit, 0);
     hidlResult = mTuner->cancel();
-    EXPECT_EQ(Status::EX_NONE, hidlResult.getStatus().exceptionCode());
+    EXPECT_TRUE(hidlResult.isOk());
     EXPECT_EQ(Result::OK, hidlResult);
 }
 
diff --git a/camera/Android.bp b/camera/Android.bp
index a373bf4..e379e49 100644
--- a/camera/Android.bp
+++ b/camera/Android.bp
@@ -1,8 +1,12 @@
 // This is an autogenerated file, do not edit.
 subdirs = [
     "common/1.0",
+    "common/1.0/default",
     "device/1.0",
     "device/3.2",
+    "device/3.2/default",
     "metadata/3.2",
     "provider/2.4",
+    "provider/2.4/default",
+    "provider/2.4/vts/functional",
 ]
diff --git a/camera/common/1.0/default/Android.bp b/camera/common/1.0/default/Android.bp
new file mode 100644
index 0000000..af0ff6e
--- /dev/null
+++ b/camera/common/1.0/default/Android.bp
@@ -0,0 +1,15 @@
+cc_library_static {
+    name: "android.hardware.camera.common@1.0-helper",
+    srcs: ["CameraModule.cpp", "CameraMetadata.cpp", "VendorTagDescriptor.cpp"],
+    cflags: [
+        "-Werror",
+        "-Wextra",
+        "-Wall",
+    ],
+    shared_libs: [
+        "liblog",
+        "libhardware",
+        "libcamera_metadata"],
+    include_dirs: ["system/media/private/camera/include"],
+    export_include_dirs : ["include"]
+}
diff --git a/camera/common/1.0/default/CameraMetadata.cpp b/camera/common/1.0/default/CameraMetadata.cpp
new file mode 100644
index 0000000..44c2040
--- /dev/null
+++ b/camera/common/1.0/default/CameraMetadata.cpp
@@ -0,0 +1,568 @@
+/*
+ * Copyright (C) 2016 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_NDEBUG 0
+
+#define LOG_TAG "CamComm1.0-MD"
+#include <utils/Log.h>
+#include <utils/Errors.h>
+
+#include "CameraMetadata.h"
+#include "VendorTagDescriptor.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace common {
+namespace V1_0 {
+namespace helper {
+
+#define ALIGN_TO(val, alignment) \
+    (((uintptr_t)(val) + ((alignment) - 1)) & ~((alignment) - 1))
+
+CameraMetadata::CameraMetadata() :
+        mBuffer(NULL), mLocked(false) {
+}
+
+CameraMetadata::CameraMetadata(size_t entryCapacity, size_t dataCapacity) :
+        mLocked(false)
+{
+    mBuffer = allocate_camera_metadata(entryCapacity, dataCapacity);
+}
+
+CameraMetadata::CameraMetadata(const CameraMetadata &other) :
+        mLocked(false) {
+    mBuffer = clone_camera_metadata(other.mBuffer);
+}
+
+CameraMetadata::CameraMetadata(camera_metadata_t *buffer) :
+        mBuffer(NULL), mLocked(false) {
+    acquire(buffer);
+}
+
+CameraMetadata &CameraMetadata::operator=(const CameraMetadata &other) {
+    return operator=(other.mBuffer);
+}
+
+CameraMetadata &CameraMetadata::operator=(const camera_metadata_t *buffer) {
+    if (mLocked) {
+        ALOGE("%s: Assignment to a locked CameraMetadata!", __FUNCTION__);
+        return *this;
+    }
+
+    if (CC_LIKELY(buffer != mBuffer)) {
+        camera_metadata_t *newBuffer = clone_camera_metadata(buffer);
+        clear();
+        mBuffer = newBuffer;
+    }
+    return *this;
+}
+
+CameraMetadata::~CameraMetadata() {
+    mLocked = false;
+    clear();
+}
+
+const camera_metadata_t* CameraMetadata::getAndLock() const {
+    mLocked = true;
+    return mBuffer;
+}
+
+status_t CameraMetadata::unlock(const camera_metadata_t *buffer) const {
+    if (!mLocked) {
+        ALOGE("%s: Can't unlock a non-locked CameraMetadata!", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+    if (buffer != mBuffer) {
+        ALOGE("%s: Can't unlock CameraMetadata with wrong pointer!",
+                __FUNCTION__);
+        return BAD_VALUE;
+    }
+    mLocked = false;
+    return OK;
+}
+
+camera_metadata_t* CameraMetadata::release() {
+    if (mLocked) {
+        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+        return NULL;
+    }
+    camera_metadata_t *released = mBuffer;
+    mBuffer = NULL;
+    return released;
+}
+
+void CameraMetadata::clear() {
+    if (mLocked) {
+        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+        return;
+    }
+    if (mBuffer) {
+        free_camera_metadata(mBuffer);
+        mBuffer = NULL;
+    }
+}
+
+void CameraMetadata::acquire(camera_metadata_t *buffer) {
+    if (mLocked) {
+        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+        return;
+    }
+    clear();
+    mBuffer = buffer;
+
+    ALOGE_IF(validate_camera_metadata_structure(mBuffer, /*size*/NULL) != OK,
+             "%s: Failed to validate metadata structure %p",
+             __FUNCTION__, buffer);
+}
+
+void CameraMetadata::acquire(CameraMetadata &other) {
+    if (mLocked) {
+        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+        return;
+    }
+    acquire(other.release());
+}
+
+status_t CameraMetadata::append(const CameraMetadata &other) {
+    return append(other.mBuffer);
+}
+
+status_t CameraMetadata::append(const camera_metadata_t* other) {
+    if (mLocked) {
+        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+    size_t extraEntries = get_camera_metadata_entry_count(other);
+    size_t extraData = get_camera_metadata_data_count(other);
+    resizeIfNeeded(extraEntries, extraData);
+
+    return append_camera_metadata(mBuffer, other);
+}
+
+size_t CameraMetadata::entryCount() const {
+    return (mBuffer == NULL) ? 0 :
+            get_camera_metadata_entry_count(mBuffer);
+}
+
+bool CameraMetadata::isEmpty() const {
+    return entryCount() == 0;
+}
+
+status_t CameraMetadata::sort() {
+    if (mLocked) {
+        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+    return sort_camera_metadata(mBuffer);
+}
+
+status_t CameraMetadata::checkType(uint32_t tag, uint8_t expectedType) {
+    int tagType = get_camera_metadata_tag_type(tag);
+    if ( CC_UNLIKELY(tagType == -1)) {
+        ALOGE("Update metadata entry: Unknown tag %d", tag);
+        return INVALID_OPERATION;
+    }
+    if ( CC_UNLIKELY(tagType != expectedType) ) {
+        ALOGE("Mismatched tag type when updating entry %s (%d) of type %s; "
+                "got type %s data instead ",
+                get_camera_metadata_tag_name(tag), tag,
+                camera_metadata_type_names[tagType],
+                camera_metadata_type_names[expectedType]);
+        return INVALID_OPERATION;
+    }
+    return OK;
+}
+
+status_t CameraMetadata::update(uint32_t tag,
+        const int32_t *data, size_t data_count) {
+    status_t res;
+    if (mLocked) {
+        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+    if ( (res = checkType(tag, TYPE_INT32)) != OK) {
+        return res;
+    }
+    return updateImpl(tag, (const void*)data, data_count);
+}
+
+status_t CameraMetadata::update(uint32_t tag,
+        const uint8_t *data, size_t data_count) {
+    status_t res;
+    if (mLocked) {
+        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+    if ( (res = checkType(tag, TYPE_BYTE)) != OK) {
+        return res;
+    }
+    return updateImpl(tag, (const void*)data, data_count);
+}
+
+status_t CameraMetadata::update(uint32_t tag,
+        const float *data, size_t data_count) {
+    status_t res;
+    if (mLocked) {
+        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+    if ( (res = checkType(tag, TYPE_FLOAT)) != OK) {
+        return res;
+    }
+    return updateImpl(tag, (const void*)data, data_count);
+}
+
+status_t CameraMetadata::update(uint32_t tag,
+        const int64_t *data, size_t data_count) {
+    status_t res;
+    if (mLocked) {
+        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+    if ( (res = checkType(tag, TYPE_INT64)) != OK) {
+        return res;
+    }
+    return updateImpl(tag, (const void*)data, data_count);
+}
+
+status_t CameraMetadata::update(uint32_t tag,
+        const double *data, size_t data_count) {
+    status_t res;
+    if (mLocked) {
+        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+    if ( (res = checkType(tag, TYPE_DOUBLE)) != OK) {
+        return res;
+    }
+    return updateImpl(tag, (const void*)data, data_count);
+}
+
+status_t CameraMetadata::update(uint32_t tag,
+        const camera_metadata_rational_t *data, size_t data_count) {
+    status_t res;
+    if (mLocked) {
+        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+    if ( (res = checkType(tag, TYPE_RATIONAL)) != OK) {
+        return res;
+    }
+    return updateImpl(tag, (const void*)data, data_count);
+}
+
+status_t CameraMetadata::update(uint32_t tag,
+        const String8 &string) {
+    status_t res;
+    if (mLocked) {
+        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+    if ( (res = checkType(tag, TYPE_BYTE)) != OK) {
+        return res;
+    }
+    // string.size() doesn't count the null termination character.
+    return updateImpl(tag, (const void*)string.string(), string.size() + 1);
+}
+
+status_t CameraMetadata::update(const camera_metadata_ro_entry &entry) {
+    status_t res;
+    if (mLocked) {
+        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+    if ( (res = checkType(entry.tag, entry.type)) != OK) {
+        return res;
+    }
+    return updateImpl(entry.tag, (const void*)entry.data.u8, entry.count);
+}
+
+status_t CameraMetadata::updateImpl(uint32_t tag, const void *data,
+        size_t data_count) {
+    status_t res;
+    if (mLocked) {
+        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+    int type = get_camera_metadata_tag_type(tag);
+    if (type == -1) {
+        ALOGE("%s: Tag %d not found", __FUNCTION__, tag);
+        return BAD_VALUE;
+    }
+    // Safety check - ensure that data isn't pointing to this metadata, since
+    // that would get invalidated if a resize is needed
+    size_t bufferSize = get_camera_metadata_size(mBuffer);
+    uintptr_t bufAddr = reinterpret_cast<uintptr_t>(mBuffer);
+    uintptr_t dataAddr = reinterpret_cast<uintptr_t>(data);
+    if (dataAddr > bufAddr && dataAddr < (bufAddr + bufferSize)) {
+        ALOGE("%s: Update attempted with data from the same metadata buffer!",
+                __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+
+    size_t data_size = calculate_camera_metadata_entry_data_size(type,
+            data_count);
+
+    res = resizeIfNeeded(1, data_size);
+
+    if (res == OK) {
+        camera_metadata_entry_t entry;
+        res = find_camera_metadata_entry(mBuffer, tag, &entry);
+        if (res == NAME_NOT_FOUND) {
+            res = add_camera_metadata_entry(mBuffer,
+                    tag, data, data_count);
+        } else if (res == OK) {
+            res = update_camera_metadata_entry(mBuffer,
+                    entry.index, data, data_count, NULL);
+        }
+    }
+
+    if (res != OK) {
+        ALOGE("%s: Unable to update metadata entry %s.%s (%x): %s (%d)",
+                __FUNCTION__, get_camera_metadata_section_name(tag),
+                get_camera_metadata_tag_name(tag), tag, strerror(-res), res);
+    }
+
+    IF_ALOGV() {
+        ALOGE_IF(validate_camera_metadata_structure(mBuffer, /*size*/NULL) !=
+                 OK,
+
+                 "%s: Failed to validate metadata structure after update %p",
+                 __FUNCTION__, mBuffer);
+    }
+
+    return res;
+}
+
+bool CameraMetadata::exists(uint32_t tag) const {
+    camera_metadata_ro_entry entry;
+    return find_camera_metadata_ro_entry(mBuffer, tag, &entry) == 0;
+}
+
+camera_metadata_entry_t CameraMetadata::find(uint32_t tag) {
+    status_t res;
+    camera_metadata_entry entry;
+    if (mLocked) {
+        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+        entry.count = 0;
+        return entry;
+    }
+    res = find_camera_metadata_entry(mBuffer, tag, &entry);
+    if (CC_UNLIKELY( res != OK )) {
+        entry.count = 0;
+        entry.data.u8 = NULL;
+    }
+    return entry;
+}
+
+camera_metadata_ro_entry_t CameraMetadata::find(uint32_t tag) const {
+    status_t res;
+    camera_metadata_ro_entry entry;
+    res = find_camera_metadata_ro_entry(mBuffer, tag, &entry);
+    if (CC_UNLIKELY( res != OK )) {
+        entry.count = 0;
+        entry.data.u8 = NULL;
+    }
+    return entry;
+}
+
+status_t CameraMetadata::erase(uint32_t tag) {
+    camera_metadata_entry_t entry;
+    status_t res;
+    if (mLocked) {
+        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+    res = find_camera_metadata_entry(mBuffer, tag, &entry);
+    if (res == NAME_NOT_FOUND) {
+        return OK;
+    } else if (res != OK) {
+        ALOGE("%s: Error looking for entry %s.%s (%x): %s %d",
+                __FUNCTION__,
+                get_camera_metadata_section_name(tag),
+                get_camera_metadata_tag_name(tag), tag, strerror(-res), res);
+        return res;
+    }
+    res = delete_camera_metadata_entry(mBuffer, entry.index);
+    if (res != OK) {
+        ALOGE("%s: Error deleting entry %s.%s (%x): %s %d",
+                __FUNCTION__,
+                get_camera_metadata_section_name(tag),
+                get_camera_metadata_tag_name(tag), tag, strerror(-res), res);
+    }
+    return res;
+}
+
+void CameraMetadata::dump(int fd, int verbosity, int indentation) const {
+    dump_indented_camera_metadata(mBuffer, fd, verbosity, indentation);
+}
+
+status_t CameraMetadata::resizeIfNeeded(size_t extraEntries, size_t extraData) {
+    if (mBuffer == NULL) {
+        mBuffer = allocate_camera_metadata(extraEntries * 2, extraData * 2);
+        if (mBuffer == NULL) {
+            ALOGE("%s: Can't allocate larger metadata buffer", __FUNCTION__);
+            return NO_MEMORY;
+        }
+    } else {
+        size_t currentEntryCount = get_camera_metadata_entry_count(mBuffer);
+        size_t currentEntryCap = get_camera_metadata_entry_capacity(mBuffer);
+        size_t newEntryCount = currentEntryCount +
+                extraEntries;
+        newEntryCount = (newEntryCount > currentEntryCap) ?
+                newEntryCount * 2 : currentEntryCap;
+
+        size_t currentDataCount = get_camera_metadata_data_count(mBuffer);
+        size_t currentDataCap = get_camera_metadata_data_capacity(mBuffer);
+        size_t newDataCount = currentDataCount +
+                extraData;
+        newDataCount = (newDataCount > currentDataCap) ?
+                newDataCount * 2 : currentDataCap;
+
+        if (newEntryCount > currentEntryCap ||
+                newDataCount > currentDataCap) {
+            camera_metadata_t *oldBuffer = mBuffer;
+            mBuffer = allocate_camera_metadata(newEntryCount,
+                    newDataCount);
+            if (mBuffer == NULL) {
+                ALOGE("%s: Can't allocate larger metadata buffer", __FUNCTION__);
+                return NO_MEMORY;
+            }
+            append_camera_metadata(mBuffer, oldBuffer);
+            free_camera_metadata(oldBuffer);
+        }
+    }
+    return OK;
+}
+
+void CameraMetadata::swap(CameraMetadata& other) {
+    if (mLocked) {
+        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+        return;
+    } else if (other.mLocked) {
+        ALOGE("%s: Other CameraMetadata is locked", __FUNCTION__);
+        return;
+    }
+
+    camera_metadata* thisBuf = mBuffer;
+    camera_metadata* otherBuf = other.mBuffer;
+
+    other.mBuffer = thisBuf;
+    mBuffer = otherBuf;
+}
+
+status_t CameraMetadata::getTagFromName(const char *name,
+        const VendorTagDescriptor* vTags, uint32_t *tag) {
+
+    if (name == nullptr || tag == nullptr) return BAD_VALUE;
+
+    size_t nameLength = strlen(name);
+
+    const SortedVector<String8> *vendorSections;
+    size_t vendorSectionCount = 0;
+
+    if (vTags != NULL) {
+        vendorSections = vTags->getAllSectionNames();
+        vendorSectionCount = vendorSections->size();
+    }
+
+    // First, find the section by the longest string match
+    const char *section = NULL;
+    size_t sectionIndex = 0;
+    size_t sectionLength = 0;
+    size_t totalSectionCount = ANDROID_SECTION_COUNT + vendorSectionCount;
+    for (size_t i = 0; i < totalSectionCount; ++i) {
+
+        const char *str = (i < ANDROID_SECTION_COUNT) ? camera_metadata_section_names[i] :
+                (*vendorSections)[i - ANDROID_SECTION_COUNT].string();
+
+        ALOGV("%s: Trying to match against section '%s'", __FUNCTION__, str);
+
+        if (strstr(name, str) == name) { // name begins with the section name
+            size_t strLength = strlen(str);
+
+            ALOGV("%s: Name begins with section name", __FUNCTION__);
+
+            // section name is the longest we've found so far
+            if (section == NULL || sectionLength < strLength) {
+                section = str;
+                sectionIndex = i;
+                sectionLength = strLength;
+
+                ALOGV("%s: Found new best section (%s)", __FUNCTION__, section);
+            }
+        }
+    }
+
+    // TODO: Make above get_camera_metadata_section_from_name ?
+
+    if (section == NULL) {
+        return NAME_NOT_FOUND;
+    } else {
+        ALOGV("%s: Found matched section '%s' (%zu)",
+              __FUNCTION__, section, sectionIndex);
+    }
+
+    // Get the tag name component of the name
+    const char *nameTagName = name + sectionLength + 1; // x.y.z -> z
+    if (sectionLength + 1 >= nameLength) {
+        return BAD_VALUE;
+    }
+
+    // Match rest of name against the tag names in that section only
+    uint32_t candidateTag = 0;
+    if (sectionIndex < ANDROID_SECTION_COUNT) {
+        // Match built-in tags (typically android.*)
+        uint32_t tagBegin, tagEnd; // [tagBegin, tagEnd)
+        tagBegin = camera_metadata_section_bounds[sectionIndex][0];
+        tagEnd = camera_metadata_section_bounds[sectionIndex][1];
+
+        for (candidateTag = tagBegin; candidateTag < tagEnd; ++candidateTag) {
+            const char *tagName = get_camera_metadata_tag_name(candidateTag);
+
+            if (strcmp(nameTagName, tagName) == 0) {
+                ALOGV("%s: Found matched tag '%s' (%d)",
+                      __FUNCTION__, tagName, candidateTag);
+                break;
+            }
+        }
+
+        if (candidateTag == tagEnd) {
+            return NAME_NOT_FOUND;
+        }
+    } else if (vTags != NULL) {
+        // Match vendor tags (typically com.*)
+        const String8 sectionName(section);
+        const String8 tagName(nameTagName);
+
+        status_t res = OK;
+        if ((res = vTags->lookupTag(tagName, sectionName, &candidateTag)) != OK) {
+            return NAME_NOT_FOUND;
+        }
+    }
+
+    *tag = candidateTag;
+    return OK;
+}
+
+
+} // namespace helper
+} // namespace V1_0
+} // namespace common
+} // namespace camera
+} // namespace hardware
+} // namespace android
diff --git a/camera/common/1.0/default/CameraModule.cpp b/camera/common/1.0/default/CameraModule.cpp
new file mode 100644
index 0000000..5d9ae4d
--- /dev/null
+++ b/camera/common/1.0/default/CameraModule.cpp
@@ -0,0 +1,451 @@
+/*
+ * Copyright (C) 2016 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 "CamComm1.0-CamModule"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+//#define LOG_NDEBUG 0
+
+#include <utils/Trace.h>
+
+#include "CameraModule.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace common {
+namespace V1_0 {
+namespace helper {
+
+void CameraModule::deriveCameraCharacteristicsKeys(
+        uint32_t deviceVersion, CameraMetadata &chars) {
+    ATRACE_CALL();
+
+    Vector<int32_t> derivedCharKeys;
+    Vector<int32_t> derivedRequestKeys;
+    Vector<int32_t> derivedResultKeys;
+    // Keys added in HAL3.3
+    if (deviceVersion < CAMERA_DEVICE_API_VERSION_3_3) {
+        Vector<uint8_t> controlModes;
+        uint8_t data = ANDROID_CONTROL_AE_LOCK_AVAILABLE_TRUE;
+        chars.update(ANDROID_CONTROL_AE_LOCK_AVAILABLE, &data, /*count*/1);
+        data = ANDROID_CONTROL_AWB_LOCK_AVAILABLE_TRUE;
+        chars.update(ANDROID_CONTROL_AWB_LOCK_AVAILABLE, &data, /*count*/1);
+        controlModes.push(ANDROID_CONTROL_MODE_AUTO);
+        camera_metadata_entry entry = chars.find(ANDROID_CONTROL_AVAILABLE_SCENE_MODES);
+        if (entry.count > 1 || entry.data.u8[0] != ANDROID_CONTROL_SCENE_MODE_DISABLED) {
+            controlModes.push(ANDROID_CONTROL_MODE_USE_SCENE_MODE);
+        }
+
+        // Only advertise CONTROL_OFF mode if 3A manual controls are supported.
+        bool isManualAeSupported = false;
+        bool isManualAfSupported = false;
+        bool isManualAwbSupported = false;
+        entry = chars.find(ANDROID_CONTROL_AE_AVAILABLE_MODES);
+        if (entry.count > 0) {
+            for (size_t i = 0; i < entry.count; i++) {
+                if (entry.data.u8[i] == ANDROID_CONTROL_AE_MODE_OFF) {
+                    isManualAeSupported = true;
+                    break;
+                }
+            }
+        }
+        entry = chars.find(ANDROID_CONTROL_AF_AVAILABLE_MODES);
+        if (entry.count > 0) {
+            for (size_t i = 0; i < entry.count; i++) {
+                if (entry.data.u8[i] == ANDROID_CONTROL_AF_MODE_OFF) {
+                    isManualAfSupported = true;
+                    break;
+                }
+            }
+        }
+        entry = chars.find(ANDROID_CONTROL_AWB_AVAILABLE_MODES);
+        if (entry.count > 0) {
+            for (size_t i = 0; i < entry.count; i++) {
+                if (entry.data.u8[i] == ANDROID_CONTROL_AWB_MODE_OFF) {
+                    isManualAwbSupported = true;
+                    break;
+                }
+            }
+        }
+        if (isManualAeSupported && isManualAfSupported && isManualAwbSupported) {
+            controlModes.push(ANDROID_CONTROL_MODE_OFF);
+        }
+
+        chars.update(ANDROID_CONTROL_AVAILABLE_MODES, controlModes);
+
+        entry = chars.find(ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS);
+        // HAL3.2 devices passing existing CTS test should all support all LSC modes and LSC map
+        bool lensShadingModeSupported = false;
+        if (entry.count > 0) {
+            for (size_t i = 0; i < entry.count; i++) {
+                if (entry.data.i32[i] == ANDROID_SHADING_MODE) {
+                    lensShadingModeSupported = true;
+                    break;
+                }
+            }
+        }
+        Vector<uint8_t> lscModes;
+        Vector<uint8_t> lscMapModes;
+        lscModes.push(ANDROID_SHADING_MODE_FAST);
+        lscModes.push(ANDROID_SHADING_MODE_HIGH_QUALITY);
+        lscMapModes.push(ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF);
+        if (lensShadingModeSupported) {
+            lscModes.push(ANDROID_SHADING_MODE_OFF);
+            lscMapModes.push(ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_ON);
+        }
+        chars.update(ANDROID_SHADING_AVAILABLE_MODES, lscModes);
+        chars.update(ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES, lscMapModes);
+
+        derivedCharKeys.push(ANDROID_CONTROL_AE_LOCK_AVAILABLE);
+        derivedCharKeys.push(ANDROID_CONTROL_AWB_LOCK_AVAILABLE);
+        derivedCharKeys.push(ANDROID_CONTROL_AVAILABLE_MODES);
+        derivedCharKeys.push(ANDROID_SHADING_AVAILABLE_MODES);
+        derivedCharKeys.push(ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES);
+
+        // Need update android.control.availableHighSpeedVideoConfigurations since HAL3.3
+        // adds batch size to this array.
+        entry = chars.find(ANDROID_CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS);
+        if (entry.count > 0) {
+            Vector<int32_t> highSpeedConfig;
+            for (size_t i = 0; i < entry.count; i += 4) {
+                highSpeedConfig.add(entry.data.i32[i]); // width
+                highSpeedConfig.add(entry.data.i32[i + 1]); // height
+                highSpeedConfig.add(entry.data.i32[i + 2]); // fps_min
+                highSpeedConfig.add(entry.data.i32[i + 3]); // fps_max
+                highSpeedConfig.add(1); // batchSize_max. default to 1 for HAL3.2
+            }
+            chars.update(ANDROID_CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS,
+                    highSpeedConfig);
+        }
+    }
+
+    // Keys added in HAL3.4
+    if (deviceVersion < CAMERA_DEVICE_API_VERSION_3_4) {
+        // Check if HAL supports RAW_OPAQUE output
+        camera_metadata_entry entry = chars.find(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
+        bool supportRawOpaque = false;
+        bool supportAnyRaw = false;
+        const int STREAM_CONFIGURATION_SIZE = 4;
+        const int STREAM_FORMAT_OFFSET = 0;
+        const int STREAM_WIDTH_OFFSET = 1;
+        const int STREAM_HEIGHT_OFFSET = 2;
+        const int STREAM_IS_INPUT_OFFSET = 3;
+        Vector<int32_t> rawOpaqueSizes;
+
+        for (size_t i=0; i < entry.count; i += STREAM_CONFIGURATION_SIZE) {
+            int32_t format = entry.data.i32[i + STREAM_FORMAT_OFFSET];
+            int32_t width = entry.data.i32[i + STREAM_WIDTH_OFFSET];
+            int32_t height = entry.data.i32[i + STREAM_HEIGHT_OFFSET];
+            int32_t isInput = entry.data.i32[i + STREAM_IS_INPUT_OFFSET];
+            if (isInput == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
+                    format == HAL_PIXEL_FORMAT_RAW_OPAQUE) {
+                supportRawOpaque = true;
+                rawOpaqueSizes.push(width);
+                rawOpaqueSizes.push(height);
+                // 2 bytes per pixel. This rough estimation is only used when
+                // HAL does not fill in the opaque raw size
+                rawOpaqueSizes.push(width * height *2);
+            }
+            if (isInput == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
+                    (format == HAL_PIXEL_FORMAT_RAW16 ||
+                     format == HAL_PIXEL_FORMAT_RAW10 ||
+                     format == HAL_PIXEL_FORMAT_RAW12 ||
+                     format == HAL_PIXEL_FORMAT_RAW_OPAQUE)) {
+                supportAnyRaw = true;
+            }
+        }
+
+        if (supportRawOpaque) {
+            entry = chars.find(ANDROID_SENSOR_OPAQUE_RAW_SIZE);
+            if (entry.count == 0) {
+                // Fill in estimated value if HAL does not list it
+                chars.update(ANDROID_SENSOR_OPAQUE_RAW_SIZE, rawOpaqueSizes);
+                derivedCharKeys.push(ANDROID_SENSOR_OPAQUE_RAW_SIZE);
+            }
+        }
+
+        // Check if HAL supports any RAW output, if so, fill in postRawSensitivityBoost range
+        if (supportAnyRaw) {
+            int32_t defaultRange[2] = {100, 100};
+            entry = chars.find(ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE);
+            if (entry.count == 0) {
+                // Fill in default value (100, 100)
+                chars.update(
+                        ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE,
+                        defaultRange, 2);
+                derivedCharKeys.push(ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE);
+                // Actual request/results will be derived by camera device.
+                derivedRequestKeys.push(ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST);
+                derivedResultKeys.push(ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST);
+            }
+        }
+    }
+
+    // Always add a default for the pre-correction active array if the vendor chooses to omit this
+    camera_metadata_entry entry = chars.find(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE);
+    if (entry.count == 0) {
+        Vector<int32_t> preCorrectionArray;
+        entry = chars.find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE);
+        preCorrectionArray.appendArray(entry.data.i32, entry.count);
+        chars.update(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE, preCorrectionArray);
+        derivedCharKeys.push(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE);
+    }
+
+    // Add those newly added keys to AVAILABLE_CHARACTERISTICS_KEYS
+    // This has to be done at this end of this function.
+    if (derivedCharKeys.size() > 0) {
+        appendAvailableKeys(
+                chars, ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, derivedCharKeys);
+    }
+    if (derivedRequestKeys.size() > 0) {
+        appendAvailableKeys(
+                chars, ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS, derivedRequestKeys);
+    }
+    if (derivedResultKeys.size() > 0) {
+        appendAvailableKeys(
+                chars, ANDROID_REQUEST_AVAILABLE_RESULT_KEYS, derivedResultKeys);
+    }
+    return;
+}
+
+void CameraModule::appendAvailableKeys(CameraMetadata &chars,
+        int32_t keyTag, const Vector<int32_t>& appendKeys) {
+    camera_metadata_entry entry = chars.find(keyTag);
+    Vector<int32_t> availableKeys;
+    availableKeys.setCapacity(entry.count + appendKeys.size());
+    for (size_t i = 0; i < entry.count; i++) {
+        availableKeys.push(entry.data.i32[i]);
+    }
+    for (size_t i = 0; i < appendKeys.size(); i++) {
+        availableKeys.push(appendKeys[i]);
+    }
+    chars.update(keyTag, availableKeys);
+}
+
+CameraModule::CameraModule(camera_module_t *module) {
+    if (module == NULL) {
+        ALOGE("%s: camera hardware module must not be null", __FUNCTION__);
+        assert(0);
+    }
+    mModule = module;
+}
+
+CameraModule::~CameraModule()
+{
+    while (mCameraInfoMap.size() > 0) {
+        camera_info cameraInfo = mCameraInfoMap.editValueAt(0);
+        if (cameraInfo.static_camera_characteristics != NULL) {
+            free_camera_metadata(
+                    const_cast<camera_metadata_t*>(cameraInfo.static_camera_characteristics));
+        }
+        mCameraInfoMap.removeItemsAt(0);
+    }
+}
+
+int CameraModule::init() {
+    ATRACE_CALL();
+    int res = OK;
+    if (getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_4 &&
+            mModule->init != NULL) {
+        ATRACE_BEGIN("camera_module->init");
+        res = mModule->init();
+        ATRACE_END();
+    }
+    mCameraInfoMap.setCapacity(getNumberOfCameras());
+    return res;
+}
+
+int CameraModule::getCameraInfo(int cameraId, struct camera_info *info) {
+    ATRACE_CALL();
+    Mutex::Autolock lock(mCameraInfoLock);
+    if (cameraId < 0) {
+        ALOGE("%s: Invalid camera ID %d", __FUNCTION__, cameraId);
+        return -EINVAL;
+    }
+
+    // Only override static_camera_characteristics for API2 devices
+    int apiVersion = mModule->common.module_api_version;
+    if (apiVersion < CAMERA_MODULE_API_VERSION_2_0) {
+        int ret;
+        ATRACE_BEGIN("camera_module->get_camera_info");
+        ret = mModule->get_camera_info(cameraId, info);
+        // Fill in this so CameraService won't be confused by
+        // possibly 0 device_version
+        info->device_version = CAMERA_DEVICE_API_VERSION_1_0;
+        ATRACE_END();
+        return ret;
+    }
+
+    ssize_t index = mCameraInfoMap.indexOfKey(cameraId);
+    if (index == NAME_NOT_FOUND) {
+        // Get camera info from raw module and cache it
+        camera_info rawInfo, cameraInfo;
+        ATRACE_BEGIN("camera_module->get_camera_info");
+        int ret = mModule->get_camera_info(cameraId, &rawInfo);
+        ATRACE_END();
+        if (ret != 0) {
+            return ret;
+        }
+        int deviceVersion = rawInfo.device_version;
+        if (deviceVersion < CAMERA_DEVICE_API_VERSION_3_0) {
+            // static_camera_characteristics is invalid
+            *info = rawInfo;
+            return ret;
+        }
+        CameraMetadata m;
+        m = rawInfo.static_camera_characteristics;
+        deriveCameraCharacteristicsKeys(rawInfo.device_version, m);
+        cameraInfo = rawInfo;
+        cameraInfo.static_camera_characteristics = m.release();
+        index = mCameraInfoMap.add(cameraId, cameraInfo);
+    }
+
+    assert(index != NAME_NOT_FOUND);
+    // return the cached camera info
+    *info = mCameraInfoMap[index];
+    return OK;
+}
+
+int CameraModule::getDeviceVersion(int cameraId) {
+    ssize_t index = mDeviceVersionMap.indexOfKey(cameraId);
+    if (index == NAME_NOT_FOUND) {
+        int deviceVersion;
+        if (getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_0) {
+            struct camera_info info;
+            getCameraInfo(cameraId, &info);
+            deviceVersion = info.device_version;
+        } else {
+            deviceVersion = CAMERA_DEVICE_API_VERSION_1_0;
+        }
+        index = mDeviceVersionMap.add(cameraId, deviceVersion);
+    }
+    assert(index != NAME_NOT_FOUND);
+    return mDeviceVersionMap[index];
+}
+
+int CameraModule::open(const char* id, struct hw_device_t** device) {
+    int res;
+    ATRACE_BEGIN("camera_module->open");
+    res = filterOpenErrorCode(mModule->common.methods->open(&mModule->common, id, device));
+    ATRACE_END();
+    return res;
+}
+
+bool CameraModule::isOpenLegacyDefined() const {
+    if (getModuleApiVersion() < CAMERA_MODULE_API_VERSION_2_3) {
+        return false;
+    }
+    return mModule->open_legacy != NULL;
+}
+
+int CameraModule::openLegacy(
+        const char* id, uint32_t halVersion, struct hw_device_t** device) {
+    int res;
+    ATRACE_BEGIN("camera_module->open_legacy");
+    res = mModule->open_legacy(&mModule->common, id, halVersion, device);
+    ATRACE_END();
+    return res;
+}
+
+int CameraModule::getNumberOfCameras() {
+    int numCameras;
+    ATRACE_BEGIN("camera_module->get_number_of_cameras");
+    numCameras = mModule->get_number_of_cameras();
+    ATRACE_END();
+    return numCameras;
+}
+
+int CameraModule::setCallbacks(const camera_module_callbacks_t *callbacks) {
+    int res;
+    ATRACE_BEGIN("camera_module->set_callbacks");
+    res = mModule->set_callbacks(callbacks);
+    ATRACE_END();
+    return res;
+}
+
+bool CameraModule::isVendorTagDefined() const {
+    return mModule->get_vendor_tag_ops != NULL;
+}
+
+void CameraModule::getVendorTagOps(vendor_tag_ops_t* ops) {
+    if (mModule->get_vendor_tag_ops) {
+        ATRACE_BEGIN("camera_module->get_vendor_tag_ops");
+        mModule->get_vendor_tag_ops(ops);
+        ATRACE_END();
+    }
+}
+
+bool CameraModule::isSetTorchModeSupported() const {
+    if (getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_4) {
+        if (mModule->set_torch_mode == NULL) {
+            ALOGE("%s: Module 2.4 device must support set torch API!",
+                    __FUNCTION__);
+            return false;
+        }
+        return true;
+    }
+    return false;
+}
+
+int CameraModule::setTorchMode(const char* camera_id, bool enable) {
+    int res = INVALID_OPERATION;
+    if (mModule->set_torch_mode != NULL) {
+        ATRACE_BEGIN("camera_module->set_torch_mode");
+        res = mModule->set_torch_mode(camera_id, enable);
+        ATRACE_END();
+    }
+    return res;
+}
+
+status_t CameraModule::filterOpenErrorCode(status_t err) {
+    switch(err) {
+        case NO_ERROR:
+        case -EBUSY:
+        case -EINVAL:
+        case -EUSERS:
+            return err;
+        default:
+            break;
+    }
+    return -ENODEV;
+}
+
+uint16_t CameraModule::getModuleApiVersion() const {
+    return mModule->common.module_api_version;
+}
+
+const char* CameraModule::getModuleName() const {
+    return mModule->common.name;
+}
+
+uint16_t CameraModule::getHalApiVersion() const {
+    return mModule->common.hal_api_version;
+}
+
+const char* CameraModule::getModuleAuthor() const {
+    return mModule->common.author;
+}
+
+void* CameraModule::getDso() {
+    return mModule->common.dso;
+}
+
+} // namespace helper
+} // namespace V1_0
+} // namespace common
+} // namespace camera
+} // namespace hardware
+} // namespace android
diff --git a/camera/common/1.0/default/VendorTagDescriptor.cpp b/camera/common/1.0/default/VendorTagDescriptor.cpp
new file mode 100644
index 0000000..db884a8
--- /dev/null
+++ b/camera/common/1.0/default/VendorTagDescriptor.cpp
@@ -0,0 +1,367 @@
+/*
+ * Copyright (C) 2016 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 "CamComm1.0-VTDesc"
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include <utils/Mutex.h>
+#include <utils/Vector.h>
+#include <utils/SortedVector.h>
+#include <system/camera_metadata.h>
+#include <camera_metadata_hidden.h>
+
+#include "VendorTagDescriptor.h"
+
+#include <stdio.h>
+#include <string.h>
+
+namespace android {
+namespace hardware {
+namespace camera2 {
+namespace params {
+
+VendorTagDescriptor::~VendorTagDescriptor() {
+    size_t len = mReverseMapping.size();
+    for (size_t i = 0; i < len; ++i)  {
+        delete mReverseMapping[i];
+    }
+}
+
+VendorTagDescriptor::VendorTagDescriptor() :
+        mTagCount(0),
+        mVendorOps() {
+}
+
+VendorTagDescriptor::VendorTagDescriptor(const VendorTagDescriptor& src) {
+    copyFrom(src);
+}
+
+VendorTagDescriptor& VendorTagDescriptor::operator=(const VendorTagDescriptor& rhs) {
+    copyFrom(rhs);
+    return *this;
+}
+
+void VendorTagDescriptor::copyFrom(const VendorTagDescriptor& src) {
+    if (this == &src) return;
+
+    size_t len = mReverseMapping.size();
+    for (size_t i = 0; i < len; ++i) {
+        delete mReverseMapping[i];
+    }
+    mReverseMapping.clear();
+
+    len = src.mReverseMapping.size();
+    // Have to copy KeyedVectors inside mReverseMapping
+    for (size_t i = 0; i < len; ++i) {
+        KeyedVector<String8, uint32_t>* nameMapper = new KeyedVector<String8, uint32_t>();
+        *nameMapper = *(src.mReverseMapping.valueAt(i));
+        mReverseMapping.add(src.mReverseMapping.keyAt(i), nameMapper);
+    }
+    // Everything else is simple
+    mTagToNameMap = src.mTagToNameMap;
+    mTagToSectionMap = src.mTagToSectionMap;
+    mTagToTypeMap = src.mTagToTypeMap;
+    mSections = src.mSections;
+    mTagCount = src.mTagCount;
+    mVendorOps = src.mVendorOps;
+}
+
+int VendorTagDescriptor::getTagCount() const {
+    size_t size = mTagToNameMap.size();
+    if (size == 0) {
+        return VENDOR_TAG_COUNT_ERR;
+    }
+    return size;
+}
+
+void VendorTagDescriptor::getTagArray(uint32_t* tagArray) const {
+    size_t size = mTagToNameMap.size();
+    for (size_t i = 0; i < size; ++i) {
+        tagArray[i] = mTagToNameMap.keyAt(i);
+    }
+}
+
+const char* VendorTagDescriptor::getSectionName(uint32_t tag) const {
+    ssize_t index = mTagToSectionMap.indexOfKey(tag);
+    if (index < 0) {
+        return VENDOR_SECTION_NAME_ERR;
+    }
+    return mSections[mTagToSectionMap.valueAt(index)].string();
+}
+
+ssize_t VendorTagDescriptor::getSectionIndex(uint32_t tag) const {
+    return mTagToSectionMap.valueFor(tag);
+}
+
+const char* VendorTagDescriptor::getTagName(uint32_t tag) const {
+    ssize_t index = mTagToNameMap.indexOfKey(tag);
+    if (index < 0) {
+        return VENDOR_TAG_NAME_ERR;
+    }
+    return mTagToNameMap.valueAt(index).string();
+}
+
+int VendorTagDescriptor::getTagType(uint32_t tag) const {
+    ssize_t index = mTagToNameMap.indexOfKey(tag);
+    if (index < 0) {
+        return VENDOR_TAG_TYPE_ERR;
+    }
+    return mTagToTypeMap.valueFor(tag);
+}
+
+const SortedVector<String8>* VendorTagDescriptor::getAllSectionNames() const {
+    return &mSections;
+}
+
+status_t VendorTagDescriptor::lookupTag(const String8& name, const String8& section, /*out*/uint32_t* tag) const {
+    ssize_t index = mReverseMapping.indexOfKey(section);
+    if (index < 0) {
+        ALOGE("%s: Section '%s' does not exist.", __FUNCTION__, section.string());
+        return BAD_VALUE;
+    }
+
+    ssize_t nameIndex = mReverseMapping[index]->indexOfKey(name);
+    if (nameIndex < 0) {
+        ALOGE("%s: Tag name '%s' does not exist.", __FUNCTION__, name.string());
+        return BAD_VALUE;
+    }
+
+    if (tag != NULL) {
+        *tag = mReverseMapping[index]->valueAt(nameIndex);
+    }
+    return OK;
+}
+
+void VendorTagDescriptor::dump(int fd, int verbosity, int indentation) const {
+
+    size_t size = mTagToNameMap.size();
+    if (size == 0) {
+        dprintf(fd, "%*sDumping configured vendor tag descriptors: None set\n",
+                indentation, "");
+        return;
+    }
+
+    dprintf(fd, "%*sDumping configured vendor tag descriptors: %zu entries\n",
+            indentation, "", size);
+    for (size_t i = 0; i < size; ++i) {
+        uint32_t tag =  mTagToNameMap.keyAt(i);
+
+        if (verbosity < 1) {
+            dprintf(fd, "%*s0x%x\n", indentation + 2, "", tag);
+            continue;
+        }
+        String8 name = mTagToNameMap.valueAt(i);
+        uint32_t sectionId = mTagToSectionMap.valueFor(tag);
+        String8 sectionName = mSections[sectionId];
+        int type = mTagToTypeMap.valueFor(tag);
+        const char* typeName = (type >= 0 && type < NUM_TYPES) ?
+                camera_metadata_type_names[type] : "UNKNOWN";
+        dprintf(fd, "%*s0x%x (%s) with type %d (%s) defined in section %s\n", indentation + 2,
+            "", tag, name.string(), type, typeName, sectionName.string());
+    }
+
+}
+
+} // namespace params
+} // namespace camera2
+
+namespace camera {
+namespace common {
+namespace V1_0 {
+namespace helper {
+
+extern "C" {
+
+static int vendor_tag_descriptor_get_tag_count(const vendor_tag_ops_t* v);
+static void vendor_tag_descriptor_get_all_tags(const vendor_tag_ops_t* v, uint32_t* tagArray);
+static const char* vendor_tag_descriptor_get_section_name(const vendor_tag_ops_t* v, uint32_t tag);
+static const char* vendor_tag_descriptor_get_tag_name(const vendor_tag_ops_t* v, uint32_t tag);
+static int vendor_tag_descriptor_get_tag_type(const vendor_tag_ops_t* v, uint32_t tag);
+
+} /* extern "C" */
+
+static Mutex sLock;
+static sp<VendorTagDescriptor> sGlobalVendorTagDescriptor;
+
+status_t VendorTagDescriptor::createDescriptorFromOps(const vendor_tag_ops_t* vOps,
+            /*out*/
+            sp<VendorTagDescriptor>& descriptor) {
+    if (vOps == NULL) {
+        ALOGE("%s: vendor_tag_ops argument was NULL.", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    int tagCount = vOps->get_tag_count(vOps);
+    if (tagCount < 0 || tagCount > INT32_MAX) {
+        ALOGE("%s: tag count %d from vendor ops is invalid.", __FUNCTION__, tagCount);
+        return BAD_VALUE;
+    }
+
+    Vector<uint32_t> tagArray;
+    LOG_ALWAYS_FATAL_IF(tagArray.resize(tagCount) != tagCount,
+            "%s: too many (%u) vendor tags defined.", __FUNCTION__, tagCount);
+
+    vOps->get_all_tags(vOps, /*out*/tagArray.editArray());
+
+    sp<VendorTagDescriptor> desc = new VendorTagDescriptor();
+    desc->mTagCount = tagCount;
+
+    SortedVector<String8> sections;
+    KeyedVector<uint32_t, String8> tagToSectionMap;
+
+    for (size_t i = 0; i < static_cast<size_t>(tagCount); ++i) {
+        uint32_t tag = tagArray[i];
+        if (tag < CAMERA_METADATA_VENDOR_TAG_BOUNDARY) {
+            ALOGE("%s: vendor tag %d not in vendor tag section.", __FUNCTION__, tag);
+            return BAD_VALUE;
+        }
+        const char *tagName = vOps->get_tag_name(vOps, tag);
+        if (tagName == NULL) {
+            ALOGE("%s: no tag name defined for vendor tag %d.", __FUNCTION__, tag);
+            return BAD_VALUE;
+        }
+        desc->mTagToNameMap.add(tag, String8(tagName));
+        const char *sectionName = vOps->get_section_name(vOps, tag);
+        if (sectionName == NULL) {
+            ALOGE("%s: no section name defined for vendor tag %d.", __FUNCTION__, tag);
+            return BAD_VALUE;
+        }
+
+        String8 sectionString(sectionName);
+
+        sections.add(sectionString);
+        tagToSectionMap.add(tag, sectionString);
+
+        int tagType = vOps->get_tag_type(vOps, tag);
+        if (tagType < 0 || tagType >= NUM_TYPES) {
+            ALOGE("%s: tag type %d from vendor ops does not exist.", __FUNCTION__, tagType);
+            return BAD_VALUE;
+        }
+        desc->mTagToTypeMap.add(tag, tagType);
+    }
+
+    desc->mSections = sections;
+
+    for (size_t i = 0; i < static_cast<size_t>(tagCount); ++i) {
+        uint32_t tag = tagArray[i];
+        String8 sectionString = tagToSectionMap.valueFor(tag);
+
+        // Set up tag to section index map
+        ssize_t index = sections.indexOf(sectionString);
+        LOG_ALWAYS_FATAL_IF(index < 0, "index %zd must be non-negative", index);
+        desc->mTagToSectionMap.add(tag, static_cast<uint32_t>(index));
+
+        // Set up reverse mapping
+        ssize_t reverseIndex = -1;
+        if ((reverseIndex = desc->mReverseMapping.indexOfKey(sectionString)) < 0) {
+            KeyedVector<String8, uint32_t>* nameMapper = new KeyedVector<String8, uint32_t>();
+            reverseIndex = desc->mReverseMapping.add(sectionString, nameMapper);
+        }
+        desc->mReverseMapping[reverseIndex]->add(desc->mTagToNameMap.valueFor(tag), tag);
+    }
+
+    descriptor = desc;
+    return OK;
+}
+
+status_t VendorTagDescriptor::setAsGlobalVendorTagDescriptor(const sp<VendorTagDescriptor>& desc) {
+    status_t res = OK;
+    Mutex::Autolock al(sLock);
+    sGlobalVendorTagDescriptor = desc;
+
+    vendor_tag_ops_t* opsPtr = NULL;
+    if (desc != NULL) {
+        opsPtr = &(desc->mVendorOps);
+        opsPtr->get_tag_count = vendor_tag_descriptor_get_tag_count;
+        opsPtr->get_all_tags = vendor_tag_descriptor_get_all_tags;
+        opsPtr->get_section_name = vendor_tag_descriptor_get_section_name;
+        opsPtr->get_tag_name = vendor_tag_descriptor_get_tag_name;
+        opsPtr->get_tag_type = vendor_tag_descriptor_get_tag_type;
+    }
+    if((res = set_camera_metadata_vendor_ops(opsPtr)) != OK) {
+        ALOGE("%s: Could not set vendor tag descriptor, received error %s (%d)."
+                , __FUNCTION__, strerror(-res), res);
+    }
+    return res;
+}
+
+void VendorTagDescriptor::clearGlobalVendorTagDescriptor() {
+    Mutex::Autolock al(sLock);
+    set_camera_metadata_vendor_ops(NULL);
+    sGlobalVendorTagDescriptor.clear();
+}
+
+sp<VendorTagDescriptor> VendorTagDescriptor::getGlobalVendorTagDescriptor() {
+    Mutex::Autolock al(sLock);
+    return sGlobalVendorTagDescriptor;
+}
+
+extern "C" {
+
+int vendor_tag_descriptor_get_tag_count(const vendor_tag_ops_t* /*v*/) {
+    Mutex::Autolock al(sLock);
+    if (sGlobalVendorTagDescriptor == NULL) {
+        ALOGE("%s: Vendor tag descriptor not initialized.", __FUNCTION__);
+        return VENDOR_TAG_COUNT_ERR;
+    }
+    return sGlobalVendorTagDescriptor->getTagCount();
+}
+
+void vendor_tag_descriptor_get_all_tags(const vendor_tag_ops_t* /*v*/, uint32_t* tagArray) {
+    Mutex::Autolock al(sLock);
+    if (sGlobalVendorTagDescriptor == NULL) {
+        ALOGE("%s: Vendor tag descriptor not initialized.", __FUNCTION__);
+        return;
+    }
+    sGlobalVendorTagDescriptor->getTagArray(tagArray);
+}
+
+const char* vendor_tag_descriptor_get_section_name(const vendor_tag_ops_t* /*v*/, uint32_t tag) {
+    Mutex::Autolock al(sLock);
+    if (sGlobalVendorTagDescriptor == NULL) {
+        ALOGE("%s: Vendor tag descriptor not initialized.", __FUNCTION__);
+        return VENDOR_SECTION_NAME_ERR;
+    }
+    return sGlobalVendorTagDescriptor->getSectionName(tag);
+}
+
+const char* vendor_tag_descriptor_get_tag_name(const vendor_tag_ops_t* /*v*/, uint32_t tag) {
+    Mutex::Autolock al(sLock);
+    if (sGlobalVendorTagDescriptor == NULL) {
+        ALOGE("%s: Vendor tag descriptor not initialized.", __FUNCTION__);
+        return VENDOR_TAG_NAME_ERR;
+    }
+    return sGlobalVendorTagDescriptor->getTagName(tag);
+}
+
+int vendor_tag_descriptor_get_tag_type(const vendor_tag_ops_t* /*v*/, uint32_t tag) {
+    Mutex::Autolock al(sLock);
+    if (sGlobalVendorTagDescriptor == NULL) {
+        ALOGE("%s: Vendor tag descriptor not initialized.", __FUNCTION__);
+        return VENDOR_TAG_TYPE_ERR;
+    }
+    return sGlobalVendorTagDescriptor->getTagType(tag);
+}
+
+} /* extern "C" */
+
+} // namespace helper
+} // namespace V1_0
+} // namespace common
+} // namespace camera
+} // namespace hardware
+} // namespace android
diff --git a/camera/common/1.0/default/include/CameraMetadata.h b/camera/common/1.0/default/include/CameraMetadata.h
new file mode 100644
index 0000000..d5e4d56
--- /dev/null
+++ b/camera/common/1.0/default/include/CameraMetadata.h
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2016 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 CAMERA_COMMON_1_0_CAMERAMETADATA_H
+#define CAMERA_COMMON_1_0_CAMERAMETADATA_H
+
+#include "system/camera_metadata.h"
+
+#include <utils/String8.h>
+#include <utils/Vector.h>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace common {
+namespace V1_0 {
+namespace helper {
+
+class VendorTagDescriptor;
+
+/**
+ * A convenience wrapper around the C-based camera_metadata_t library.
+ */
+class CameraMetadata {
+  public:
+    /** Creates an empty object; best used when expecting to acquire contents
+     * from elsewhere */
+    CameraMetadata();
+    /** Creates an object with space for entryCapacity entries, with
+     * dataCapacity extra storage */
+    CameraMetadata(size_t entryCapacity, size_t dataCapacity = 10);
+
+    ~CameraMetadata();
+
+    /** Takes ownership of passed-in buffer */
+    CameraMetadata(camera_metadata_t *buffer);
+    /** Clones the metadata */
+    CameraMetadata(const CameraMetadata &other);
+
+    /**
+     * Assignment clones metadata buffer.
+     */
+    CameraMetadata &operator=(const CameraMetadata &other);
+    CameraMetadata &operator=(const camera_metadata_t *buffer);
+
+    /**
+     * Get reference to the underlying metadata buffer. Ownership remains with
+     * the CameraMetadata object, but non-const CameraMetadata methods will not
+     * work until unlock() is called. Note that the lock has nothing to do with
+     * thread-safety, it simply prevents the camera_metadata_t pointer returned
+     * here from being accidentally invalidated by CameraMetadata operations.
+     */
+    const camera_metadata_t* getAndLock() const;
+
+    /**
+     * Unlock the CameraMetadata for use again. After this unlock, the pointer
+     * given from getAndLock() may no longer be used. The pointer passed out
+     * from getAndLock must be provided to guarantee that the right object is
+     * being unlocked.
+     */
+    status_t unlock(const camera_metadata_t *buffer) const;
+
+    /**
+     * Release a raw metadata buffer to the caller. After this call,
+     * CameraMetadata no longer references the buffer, and the caller takes
+     * responsibility for freeing the raw metadata buffer (using
+     * free_camera_metadata()), or for handing it to another CameraMetadata
+     * instance.
+     */
+    camera_metadata_t* release();
+
+    /**
+     * Clear the metadata buffer and free all storage used by it
+     */
+    void clear();
+
+    /**
+     * Acquire a raw metadata buffer from the caller. After this call,
+     * the caller no longer owns the raw buffer, and must not free or manipulate it.
+     * If CameraMetadata already contains metadata, it is freed.
+     */
+    void acquire(camera_metadata_t* buffer);
+
+    /**
+     * Acquires raw buffer from other CameraMetadata object. After the call, the argument
+     * object no longer has any metadata.
+     */
+    void acquire(CameraMetadata &other);
+
+    /**
+     * Append metadata from another CameraMetadata object.
+     */
+    status_t append(const CameraMetadata &other);
+
+    /**
+     * Append metadata from a raw camera_metadata buffer
+     */
+    status_t append(const camera_metadata* other);
+
+    /**
+     * Number of metadata entries.
+     */
+    size_t entryCount() const;
+
+    /**
+     * Is the buffer empty (no entires)
+     */
+    bool isEmpty() const;
+
+    /**
+     * Sort metadata buffer for faster find
+     */
+    status_t sort();
+
+    /**
+     * Update metadata entry. Will create entry if it doesn't exist already, and
+     * will reallocate the buffer if insufficient space exists. Overloaded for
+     * the various types of valid data.
+     */
+    status_t update(uint32_t tag,
+            const uint8_t *data, size_t data_count);
+    status_t update(uint32_t tag,
+            const int32_t *data, size_t data_count);
+    status_t update(uint32_t tag,
+            const float *data, size_t data_count);
+    status_t update(uint32_t tag,
+            const int64_t *data, size_t data_count);
+    status_t update(uint32_t tag,
+            const double *data, size_t data_count);
+    status_t update(uint32_t tag,
+            const camera_metadata_rational_t *data, size_t data_count);
+    status_t update(uint32_t tag,
+            const String8 &string);
+    status_t update(const camera_metadata_ro_entry &entry);
+
+
+    template<typename T>
+    status_t update(uint32_t tag, Vector<T> data) {
+        return update(tag, data.array(), data.size());
+    }
+
+    /**
+     * Check if a metadata entry exists for a given tag id
+     *
+     */
+    bool exists(uint32_t tag) const;
+
+    /**
+     * Get metadata entry by tag id
+     */
+    camera_metadata_entry find(uint32_t tag);
+
+    /**
+     * Get metadata entry by tag id, with no editing
+     */
+    camera_metadata_ro_entry find(uint32_t tag) const;
+
+    /**
+     * Delete metadata entry by tag
+     */
+    status_t erase(uint32_t tag);
+
+    /**
+     * Swap the underlying camera metadata between this and the other
+     * metadata object.
+     */
+    void swap(CameraMetadata &other);
+
+    /**
+     * Dump contents into FD for debugging. The verbosity levels are
+     * 0: Tag entry information only, no data values
+     * 1: Level 0 plus at most 16 data values per entry
+     * 2: All information
+     *
+     * The indentation parameter sets the number of spaces to add to the start
+     * each line of output.
+     */
+    void dump(int fd, int verbosity = 1, int indentation = 0) const;
+
+    /**
+     * Find tag id for a given tag name, also checking vendor tags if available.
+     * On success, returns OK and writes the tag id into tag.
+     *
+     * This is a slow method.
+     */
+    static status_t getTagFromName(const char *name,
+            const VendorTagDescriptor* vTags, uint32_t *tag);
+
+  private:
+    camera_metadata_t *mBuffer;
+    mutable bool       mLocked;
+
+    /**
+     * Check if tag has a given type
+     */
+    status_t checkType(uint32_t tag, uint8_t expectedType);
+
+    /**
+     * Base update entry method
+     */
+    status_t updateImpl(uint32_t tag, const void *data, size_t data_count);
+
+    /**
+     * Resize metadata buffer if needed by reallocating it and copying it over.
+     */
+    status_t resizeIfNeeded(size_t extraEntries, size_t extraData);
+
+};
+
+} // namespace helper
+} // namespace V1_0
+} // namespace common
+} // namespace camera
+} // namespace hardware
+} // namespace android
+
+#endif
diff --git a/camera/common/1.0/default/include/CameraModule.h b/camera/common/1.0/default/include/CameraModule.h
new file mode 100644
index 0000000..68d4f90
--- /dev/null
+++ b/camera/common/1.0/default/include/CameraModule.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2016 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 CAMERA_COMMON_1_0_CAMERAMODULE_H
+#define CAMERA_COMMON_1_0_CAMERAMODULE_H
+
+#include <hardware/camera.h>
+#include <utils/Mutex.h>
+#include <utils/KeyedVector.h>
+
+#include "CameraMetadata.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace common {
+namespace V1_0 {
+namespace helper {
+/**
+ * A wrapper class for HAL camera module.
+ *
+ * This class wraps camera_module_t returned from HAL to provide a wrapped
+ * get_camera_info implementation which CameraService generates some
+ * camera characteristics keys defined in newer HAL version on an older HAL.
+ */
+class CameraModule : public RefBase {
+public:
+    explicit CameraModule(camera_module_t *module);
+    virtual ~CameraModule();
+
+    // Must be called after construction
+    // Returns OK on success, NO_INIT on failure
+    int init();
+
+    int getCameraInfo(int cameraId, struct camera_info *info);
+    int getDeviceVersion(int cameraId);
+    int getNumberOfCameras(void);
+    int open(const char* id, struct hw_device_t** device);
+    bool isOpenLegacyDefined() const;
+    int openLegacy(const char* id, uint32_t halVersion, struct hw_device_t** device);
+    int setCallbacks(const camera_module_callbacks_t *callbacks);
+    bool isVendorTagDefined() const;
+    void getVendorTagOps(vendor_tag_ops_t* ops);
+    bool isSetTorchModeSupported() const;
+    int setTorchMode(const char* camera_id, bool enable);
+    uint16_t getModuleApiVersion() const;
+    const char* getModuleName() const;
+    uint16_t getHalApiVersion() const;
+    const char* getModuleAuthor() const;
+    // Only used by CameraModuleFixture native test. Do NOT use elsewhere.
+    void *getDso();
+
+private:
+    // Derive camera characteristics keys defined after HAL device version
+    static void deriveCameraCharacteristicsKeys(uint32_t deviceVersion, CameraMetadata &chars);
+    // Helper function to append available[request|result|chars]Keys
+    static void appendAvailableKeys(CameraMetadata &chars,
+            int32_t keyTag, const Vector<int32_t>& appendKeys);
+    status_t filterOpenErrorCode(status_t err);
+    camera_module_t *mModule;
+    KeyedVector<int, camera_info> mCameraInfoMap;
+    KeyedVector<int, int> mDeviceVersionMap;
+    Mutex mCameraInfoLock;
+};
+
+} // namespace helper
+} // namespace V1_0
+} // namespace common
+} // namespace camera
+} // namespace hardware
+} // namespace android
+
+#endif
diff --git a/camera/common/1.0/default/include/VendorTagDescriptor.h b/camera/common/1.0/default/include/VendorTagDescriptor.h
new file mode 100644
index 0000000..8d8ded9
--- /dev/null
+++ b/camera/common/1.0/default/include/VendorTagDescriptor.h
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2016 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 CAMERA_COMMON_1_0_VENDORTAGDESCRIPTOR_H
+#define CAMERA_COMMON_1_0_VENDORTAGDESCRIPTOR_H
+
+#include <utils/Vector.h>
+#include <utils/KeyedVector.h>
+#include <utils/String8.h>
+#include <utils/RefBase.h>
+#include <system/camera_vendor_tags.h>
+
+#include <stdint.h>
+
+namespace android {
+namespace hardware {
+namespace camera2 {
+namespace params {
+
+/**
+ * VendorTagDescriptor objects are containers for the vendor tag
+ * definitions provided, and are typically used to pass the vendor tag
+ * information enumerated by the HAL to clients of the camera service.
+ */
+class VendorTagDescriptor {
+    public:
+        virtual ~VendorTagDescriptor();
+
+        VendorTagDescriptor();
+        VendorTagDescriptor(const VendorTagDescriptor& src);
+        VendorTagDescriptor& operator=(const VendorTagDescriptor& rhs);
+
+        void copyFrom(const VendorTagDescriptor& src);
+
+        /**
+         * The following 'get*' methods implement the corresponding
+         * functions defined in
+         * system/media/camera/include/system/camera_vendor_tags.h
+         */
+
+        // Returns the number of vendor tags defined.
+        int getTagCount() const;
+
+        // Returns an array containing the id's of vendor tags defined.
+        void getTagArray(uint32_t* tagArray) const;
+
+        // Returns the section name string for a given vendor tag id.
+        const char* getSectionName(uint32_t tag) const;
+
+        // Returns the index in section vectors returned in getAllSectionNames()
+        // for a given vendor tag id. -1 if input tag does not exist.
+        ssize_t getSectionIndex(uint32_t tag) const;
+
+        // Returns the tag name string for a given vendor tag id.
+        const char* getTagName(uint32_t tag) const;
+
+        // Returns the tag type for a given vendor tag id.
+        int getTagType(uint32_t tag) const;
+
+        /**
+         * Convenience method to get a vector containing all vendor tag
+         * sections, or an empty vector if none are defined.
+         * The pointer is valid for the lifetime of the VendorTagDescriptor,
+         * or until copyFrom is invoked.
+         */
+        const SortedVector<String8>* getAllSectionNames() const;
+
+        /**
+         * Lookup the tag id for a given tag name and section.
+         *
+         * Returns OK on success, or a negative error code.
+         */
+        status_t lookupTag(const String8& name, const String8& section, /*out*/uint32_t* tag) const;
+
+        /**
+         * Dump the currently configured vendor tags to a file descriptor.
+         */
+        void dump(int fd, int verbosity, int indentation) const;
+
+    protected:
+        KeyedVector<String8, KeyedVector<String8, uint32_t>*> mReverseMapping;
+        KeyedVector<uint32_t, String8> mTagToNameMap;
+        KeyedVector<uint32_t, uint32_t> mTagToSectionMap; // Value is offset in mSections
+        KeyedVector<uint32_t, int32_t> mTagToTypeMap;
+        SortedVector<String8> mSections;
+        // must be int32_t to be compatible with Parcel::writeInt32
+        int32_t mTagCount;
+
+        vendor_tag_ops mVendorOps;
+};
+} /* namespace params */
+} /* namespace camera2 */
+
+namespace camera {
+namespace common {
+namespace V1_0 {
+namespace helper {
+
+/**
+ * This version of VendorTagDescriptor must be stored in Android sp<>, and adds support for using it
+ * as a global tag descriptor.
+ *
+ * It's a child class of the basic hardware::camera2::params::VendorTagDescriptor since basic
+ * Parcelable objects cannot require being kept in an sp<> and still work with auto-generated AIDL
+ * interface implementations.
+ */
+class VendorTagDescriptor :
+            public ::android::hardware::camera2::params::VendorTagDescriptor,
+            public LightRefBase<VendorTagDescriptor> {
+
+  public:
+
+    /**
+     * Create a VendorTagDescriptor object from the given vendor_tag_ops_t
+     * struct.
+     *
+     * Returns OK on success, or a negative error code.
+     */
+    static status_t createDescriptorFromOps(const vendor_tag_ops_t* vOps,
+            /*out*/
+            sp<VendorTagDescriptor>& descriptor);
+
+    /**
+     * Sets the global vendor tag descriptor to use for this process.
+     * Camera metadata operations that access vendor tags will use the
+     * vendor tag definitions set this way.
+     *
+     * Returns OK on success, or a negative error code.
+     */
+    static status_t setAsGlobalVendorTagDescriptor(const sp<VendorTagDescriptor>& desc);
+
+    /**
+     * Returns the global vendor tag descriptor used by this process.
+     * This will contain NULL if no vendor tags are defined.
+     */
+    static sp<VendorTagDescriptor> getGlobalVendorTagDescriptor();
+
+    /**
+     * Clears the global vendor tag descriptor used by this process.
+     */
+    static void clearGlobalVendorTagDescriptor();
+
+};
+
+} // namespace helper
+} // namespace V1_0
+} // namespace common
+} // namespace camera
+} // namespace hardware
+} // namespace android
+
+#endif /* CAMERA_COMMON_1_0_VENDORTAGDESCRIPTOR_H */
diff --git a/camera/device/3.2/ICameraDeviceSession.hal b/camera/device/3.2/ICameraDeviceSession.hal
index c8cc246..e92d756 100644
--- a/camera/device/3.2/ICameraDeviceSession.hal
+++ b/camera/device/3.2/ICameraDeviceSession.hal
@@ -48,6 +48,8 @@
      *     INTERNAL_ERROR:
      *         An unexpected internal error occurred, and the default settings
      *         are not available.
+     *     ILLEGAL_ARGUMENT:
+     *         The camera HAL does not support the input template type
      *     CAMERA_DISCONNECTED:
      *         An external camera device has been disconnected, and is no longer
      *         available. This camera device interface is now stale, and a new
diff --git a/camera/device/3.2/default/Android.bp b/camera/device/3.2/default/Android.bp
new file mode 100644
index 0000000..9820220
--- /dev/null
+++ b/camera/device/3.2/default/Android.bp
@@ -0,0 +1,22 @@
+cc_library_shared {
+    name: "android.hardware.camera.device@3.2-impl",
+    srcs: ["CameraDevice.cpp",
+           "CameraDeviceSession.cpp",
+           "convert.cpp"],
+    shared_libs: [
+        "libhidlbase",
+        "libhidltransport",
+        "libhwbinder",
+        "libutils",
+        "libcutils",
+        "android.hardware.camera.device@3.2",
+        "android.hardware.camera.provider@2.4",
+        "liblog",
+        "libhardware",
+        "libcamera_metadata"
+    ],
+    static_libs: [
+        "android.hardware.camera.common@1.0-helper"
+    ],
+    export_include_dirs: ["."]
+}
diff --git a/camera/device/3.2/default/CameraDevice.cpp b/camera/device/3.2/default/CameraDevice.cpp
new file mode 100644
index 0000000..18e0e7b
--- /dev/null
+++ b/camera/device/3.2/default/CameraDevice.cpp
@@ -0,0 +1,285 @@
+/*
+ * Copyright (C) 2016 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 "CamDev@3.2-impl"
+#include <android/log.h>
+
+#include <utils/Vector.h>
+#include <utils/Trace.h>
+#include "CameraDevice.h"
+#include <include/convert.h>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_2 {
+namespace implementation {
+
+using ::android::hardware::camera::common::V1_0::Status;
+
+CameraDevice::CameraDevice(
+    sp<CameraModule> module, const std::string& cameraId,
+    const SortedVector<std::pair<std::string, std::string>>& cameraDeviceNames) :
+        mModule(module),
+        mCameraId(cameraId),
+        mDisconnected(false),
+        mCameraDeviceNames(cameraDeviceNames) {
+    mCameraIdInt = atoi(mCameraId.c_str());
+    // Should not reach here as provider also validate ID
+    if (mCameraIdInt < 0 || mCameraIdInt >= module->getNumberOfCameras()) {
+        ALOGE("%s: Invalid camera id: %s", __FUNCTION__, mCameraId.c_str());
+        mInitFail = true;
+    }
+
+    mDeviceVersion = mModule->getDeviceVersion(mCameraIdInt);
+    if (mDeviceVersion < CAMERA_DEVICE_API_VERSION_3_2) {
+        ALOGE("%s: Camera id %s does not support HAL3.2+",
+                __FUNCTION__, mCameraId.c_str());
+        mInitFail = true;
+    }
+}
+
+CameraDevice::~CameraDevice() {}
+
+Status CameraDevice::initStatus() const {
+    Mutex::Autolock _l(mLock);
+    Status status = Status::OK;
+    if (mInitFail) {
+        status = Status::INTERNAL_ERROR;
+    } else if (mDisconnected) {
+        status = Status::CAMERA_DISCONNECTED;
+    }
+    return status;
+}
+
+void CameraDevice::setConnectionStatus(bool connected) {
+    Mutex::Autolock _l(mLock);
+    mDisconnected = !connected;
+    if (mSession == nullptr) {
+        return;
+    }
+    sp<CameraDeviceSession> session = mSession.promote();
+    if (session == nullptr) {
+        return;
+    }
+    // Only notify active session disconnect events.
+    // Users will need to re-open camera after disconnect event
+    if (!connected) {
+        session->disconnect();
+    }
+    return;
+}
+
+Status CameraDevice::getHidlStatus(int status) {
+    switch (status) {
+        case 0: return Status::OK;
+        case -ENOSYS: return Status::OPERATION_NOT_SUPPORTED;
+        case -EBUSY : return Status::CAMERA_IN_USE;
+        case -EUSERS: return Status::MAX_CAMERAS_IN_USE;
+        case -ENODEV: return Status::INTERNAL_ERROR;
+        case -EINVAL: return Status::ILLEGAL_ARGUMENT;
+        default:
+            ALOGE("%s: unknown HAL status code %d", __FUNCTION__, status);
+            return Status::INTERNAL_ERROR;
+    }
+}
+
+// Methods from ::android::hardware::camera::device::V3_2::ICameraDevice follow.
+Return<void> CameraDevice::getResourceCost(getResourceCost_cb _hidl_cb)  {
+    Status status = initStatus();
+    CameraResourceCost resCost;
+    if (status == Status::OK) {
+        int cost = 100;
+        std::vector<std::string> conflicting_devices;
+        struct camera_info info;
+
+        // If using post-2.4 module version, query the cost + conflicting devices from the HAL
+        if (mModule->getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_4) {
+            int ret = mModule->getCameraInfo(mCameraIdInt, &info);
+            if (ret == OK) {
+                cost = info.resource_cost;
+                for (size_t i = 0; i < info.conflicting_devices_length; i++) {
+                    std::string cameraId(info.conflicting_devices[i]);
+                    for (const auto& pair : mCameraDeviceNames) {
+                        if (cameraId == pair.first) {
+                            conflicting_devices.push_back(pair.second);
+                        }
+                    }
+                }
+            } else {
+                status = Status::INTERNAL_ERROR;
+            }
+        }
+
+        if (status == Status::OK) {
+            resCost.resourceCost = cost;
+            resCost.conflictingDevices.resize(conflicting_devices.size());
+            for (size_t i = 0; i < conflicting_devices.size(); i++) {
+                resCost.conflictingDevices[i] = conflicting_devices[i];
+                ALOGV("CamDevice %s is conflicting with camDevice %s",
+                        mCameraId.c_str(), resCost.conflictingDevices[i].c_str());
+            }
+        }
+    }
+    _hidl_cb(status, resCost);
+    return Void();
+}
+
+Return<void> CameraDevice::getCameraCharacteristics(getCameraCharacteristics_cb _hidl_cb)  {
+    Status status = initStatus();
+    CameraMetadata cameraCharacteristics;
+    if (status == Status::OK) {
+        //Module 2.1+ codepath.
+        struct camera_info info;
+        int ret = mModule->getCameraInfo(mCameraIdInt, &info);
+        if (ret == OK) {
+            convertToHidl(info.static_camera_characteristics, &cameraCharacteristics);
+        } else {
+            ALOGE("%s: get camera info failed!", __FUNCTION__);
+            status = Status::INTERNAL_ERROR;
+        }
+    }
+    _hidl_cb(status, cameraCharacteristics);
+    return Void();
+}
+
+Return<Status> CameraDevice::setTorchMode(TorchMode mode)  {
+    if (!mModule->isSetTorchModeSupported()) {
+        return Status::METHOD_NOT_SUPPORTED;
+    }
+
+    Status status = initStatus();
+    if (status == Status::OK) {
+        bool enable = (mode == TorchMode::ON) ? true : false;
+        status = getHidlStatus(mModule->setTorchMode(mCameraId.c_str(), enable));
+    }
+    return status;
+}
+
+Return<void> CameraDevice::open(const sp<ICameraDeviceCallback>& callback, open_cb _hidl_cb)  {
+    Status status = initStatus();
+    sp<CameraDeviceSession> session = nullptr;
+
+    if (callback == nullptr) {
+        ALOGE("%s: cannot open camera %s. callback is null!",
+                __FUNCTION__, mCameraId.c_str());
+        _hidl_cb(Status::ILLEGAL_ARGUMENT, session);
+        return Void();
+    }
+
+    if (status != Status::OK) {
+        // Provider will never pass initFailed device to client, so
+        // this must be a disconnected camera
+        ALOGE("%s: cannot open camera %s. camera is disconnected!",
+                __FUNCTION__, mCameraId.c_str());
+        _hidl_cb(Status::CAMERA_DISCONNECTED, session);
+        return Void();
+    } else {
+        mLock.lock();
+
+        ALOGV("%s: Initializing device for camera %d", __FUNCTION__, mCameraIdInt);
+        session = mSession.promote();
+        if (session != nullptr && !session->isClosed()) {
+            ALOGE("%s: cannot open an already opened camera!", __FUNCTION__);
+            mLock.unlock();
+            _hidl_cb(Status::CAMERA_IN_USE, nullptr);
+            return Void();
+        }
+
+        /** Open HAL device */
+        status_t res;
+        camera3_device_t *device;
+
+        ATRACE_BEGIN("camera3->open");
+        res = mModule->open(mCameraId.c_str(),
+                reinterpret_cast<hw_device_t**>(&device));
+        ATRACE_END();
+
+        if (res != OK) {
+            ALOGE("%s: cannot open camera %s!", __FUNCTION__, mCameraId.c_str());
+            mLock.unlock();
+            _hidl_cb(getHidlStatus(res), nullptr);
+            return Void();
+        }
+
+        /** Cross-check device version */
+        if (device->common.version < CAMERA_DEVICE_API_VERSION_3_2) {
+            ALOGE("%s: Could not open camera: "
+                    "Camera device should be at least %x, reports %x instead",
+                    __FUNCTION__,
+                    CAMERA_DEVICE_API_VERSION_3_2,
+                    device->common.version);
+            device->common.close(&device->common);
+            mLock.unlock();
+            _hidl_cb(Status::ILLEGAL_ARGUMENT, nullptr);
+            return Void();
+        }
+
+        session = new CameraDeviceSession(device, callback);
+        if (session == nullptr) {
+            ALOGE("%s: camera device session allocation failed", __FUNCTION__);
+            mLock.unlock();
+            _hidl_cb(Status::INTERNAL_ERROR, nullptr);
+            return Void();
+        }
+        if (session->isInitFailed()) {
+            ALOGE("%s: camera device session init failed", __FUNCTION__);
+            session = nullptr;
+            mLock.unlock();
+            _hidl_cb(Status::INTERNAL_ERROR, nullptr);
+            return Void();
+        }
+        mSession = session;
+        mLock.unlock();
+    }
+    _hidl_cb(status, session);
+    return Void();
+}
+
+Return<void> CameraDevice::dumpState(const ::android::hardware::hidl_handle& handle)  {
+    Mutex::Autolock _l(mLock);
+    if (handle.getNativeHandle() == nullptr) {
+        ALOGE("%s: handle must not be null", __FUNCTION__);
+        return Void();
+    }
+    if (handle->numFds != 1 || handle->numInts != 0) {
+        ALOGE("%s: handle must contain 1 FD and 0 integers! Got %d FDs and %d ints",
+                __FUNCTION__, handle->numFds, handle->numInts);
+        return Void();
+    }
+    int fd = handle->data[0];
+    if (mSession == nullptr) {
+        dprintf(fd, "No active camera device session instance\n");
+        return Void();
+    }
+    sp<CameraDeviceSession> session = mSession.promote();
+    if (session == nullptr) {
+        dprintf(fd, "No active camera device session instance\n");
+        return Void();
+    }
+    // Call into active session to dump states
+    session->dumpState(handle);
+    return Void();
+}
+// End of methods from ::android::hardware::camera::device::V3_2::ICameraDevice.
+
+} // namespace implementation
+}  // namespace V3_2
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
diff --git a/camera/device/3.2/default/CameraDevice.h b/camera/device/3.2/default/CameraDevice.h
new file mode 100644
index 0000000..317eea5
--- /dev/null
+++ b/camera/device/3.2/default/CameraDevice.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2016 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_CAMERA_DEVICE_V3_2_CAMERADEVICE_H
+#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_2_CAMERADEVICE_H
+
+#include "utils/Mutex.h"
+#include "CameraModule.h"
+#include "CameraMetadata.h"
+#include "CameraDeviceSession.h"
+
+#include <android/hardware/camera/device/3.2/ICameraDevice.h>
+#include <hidl/Status.h>
+#include <hidl/MQDescriptor.h>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_2 {
+namespace implementation {
+
+using ::android::hardware::camera::device::V3_2::RequestTemplate;
+using ::android::hardware::camera::device::V3_2::ICameraDevice;
+using ::android::hardware::camera::device::V3_2::ICameraDeviceCallback;
+using ::android::hardware::camera::device::V3_2::ICameraDeviceSession;
+using ::android::hardware::camera::common::V1_0::CameraResourceCost;
+using ::android::hardware::camera::common::V1_0::Status;
+using ::android::hardware::camera::common::V1_0::TorchMode;
+using ::android::hardware::camera::common::V1_0::helper::CameraModule;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+using ::android::Mutex;
+
+/*
+ * The camera device HAL implementation is opened lazily (via the open call)
+ */
+struct CameraDevice : public ICameraDevice {
+    // Called by provider HAL. Provider HAL must ensure the uniqueness of
+    // CameraDevice object per cameraId, or there could be multiple CameraDevice
+    // trying to access the same physical camera.
+    // Also, provider will have to keep track of all CameraDevice object in
+    // order to notify CameraDevice when the underlying camera is detached
+    CameraDevice(sp<CameraModule> module,
+                 const std::string& cameraId,
+                 const SortedVector<std::pair<std::string, std::string>>& cameraDeviceNames);
+    ~CameraDevice();
+    // Caller must use this method to check if CameraDevice ctor failed
+    bool isInitFailed() { return mInitFail; }
+    // Used by provider HAL to signal external camera disconnected
+    void setConnectionStatus(bool connected);
+
+    /* Methods from ::android::hardware::camera::device::V3_2::ICameraDevice follow. */
+    // The following method can be called without opening the actual camera device
+    Return<void> getResourceCost(getResourceCost_cb _hidl_cb) override;
+    Return<void> getCameraCharacteristics(getCameraCharacteristics_cb _hidl_cb) override;
+    Return<Status> setTorchMode(TorchMode mode) override;
+
+    // Open the device HAL and also return a default capture session
+    Return<void> open(const sp<ICameraDeviceCallback>& callback, open_cb _hidl_cb) override;
+
+
+    // Forward the dump call to the opened session, or do nothing
+    Return<void> dumpState(const ::android::hardware::hidl_handle& fd) override;
+    /* End of Methods from ::android::hardware::camera::device::V3_2::ICameraDevice */
+
+private:
+    // Passed from provider HAL. Should not change.
+    sp<CameraModule> mModule;
+    const std::string mCameraId;
+    // const after ctor
+    int   mCameraIdInt;
+    int   mDeviceVersion;
+    bool  mInitFail = false;
+    // Set by provider (when external camera is connected/disconnected)
+    bool  mDisconnected;
+    wp<CameraDeviceSession> mSession = nullptr;
+
+    const SortedVector<std::pair<std::string, std::string>>& mCameraDeviceNames;
+
+    // gating access to mSession and mDisconnected
+    mutable Mutex mLock;
+
+    // convert conventional HAL status to HIDL Status
+    static Status getHidlStatus(int);
+
+    Status initStatus() const;
+};
+
+}  // namespace implementation
+}  // namespace V3_2
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_CAMERA_DEVICE_V3_2_CAMERADEVICE_H
diff --git a/camera/device/3.2/default/CameraDeviceSession.cpp b/camera/device/3.2/default/CameraDeviceSession.cpp
new file mode 100644
index 0000000..de61d83
--- /dev/null
+++ b/camera/device/3.2/default/CameraDeviceSession.cpp
@@ -0,0 +1,745 @@
+/*
+ * Copyright (C) 2016 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 "CamDevSession@3.2-impl"
+#include <android/log.h>
+
+#include <utils/Trace.h>
+#include <hardware/gralloc.h>
+#include <hardware/gralloc1.h>
+#include "CameraDeviceSession.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_2 {
+namespace implementation {
+
+namespace {
+
+// Copy pasted from Hwc.cpp. Use this until gralloc mapper HAL is working
+class HandleImporter {
+public:
+    HandleImporter() : mInitialized(false) {}
+
+    bool initialize()
+    {
+        // allow only one client
+        if (mInitialized) {
+            return false;
+        }
+
+        if (!openGralloc()) {
+            return false;
+        }
+
+        mInitialized = true;
+        return true;
+    }
+
+    void cleanup()
+    {
+        if (!mInitialized) {
+            return;
+        }
+
+        closeGralloc();
+        mInitialized = false;
+    }
+
+    // In IComposer, any buffer_handle_t is owned by the caller and we need to
+    // make a clone for hwcomposer2.  We also need to translate empty handle
+    // to nullptr.  This function does that, in-place.
+    bool importBuffer(buffer_handle_t& handle)
+    {
+        if (!handle->numFds && !handle->numInts) {
+            handle = nullptr;
+            return true;
+        }
+
+        buffer_handle_t clone = cloneBuffer(handle);
+        if (!clone) {
+            return false;
+        }
+
+        handle = clone;
+        return true;
+    }
+
+    void freeBuffer(buffer_handle_t handle)
+    {
+        if (!handle) {
+            return;
+        }
+
+        releaseBuffer(handle);
+    }
+
+    bool importFence(const native_handle_t* handle, int& fd)
+    {
+        if (handle == nullptr || handle->numFds == 0) {
+            fd = -1;
+        } else if (handle->numFds == 1) {
+//TODO(b/34110242): make this hidl transport agnostic
+#ifdef BINDERIZED
+            fd = dup(handle->data[0]);
+#else
+            fd = handle->data[0];
+#endif
+            if (fd < 0) {
+                ALOGE("failed to dup fence fd %d", handle->data[0]);
+                return false;
+            }
+        } else {
+            ALOGE("invalid fence handle with %d file descriptors",
+                    handle->numFds);
+            return false;
+        }
+
+        return true;
+    }
+
+    void closeFence(int fd)
+    {
+#ifdef BINDERIZED
+        if (fd >= 0) {
+            close(fd);
+        }
+#else
+        (void) fd;
+#endif
+    }
+
+private:
+    bool mInitialized;
+
+    // Some existing gralloc drivers do not support retaining more than once,
+    // when we are in passthrough mode.
+#ifdef BINDERIZED
+    bool openGralloc()
+    {
+        const hw_module_t* module;
+        int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
+        if (err) {
+            ALOGE("failed to get gralloc module");
+            return false;
+        }
+
+        uint8_t major = (module->module_api_version >> 8) & 0xff;
+        if (major > 1) {
+            ALOGE("unknown gralloc module major version %d", major);
+            return false;
+        }
+
+        if (major == 1) {
+            err = gralloc1_open(module, &mDevice);
+            if (err) {
+                ALOGE("failed to open gralloc1 device");
+                return false;
+            }
+
+            mRetain = reinterpret_cast<GRALLOC1_PFN_RETAIN>(
+                    mDevice->getFunction(mDevice, GRALLOC1_FUNCTION_RETAIN));
+            mRelease = reinterpret_cast<GRALLOC1_PFN_RELEASE>(
+                    mDevice->getFunction(mDevice, GRALLOC1_FUNCTION_RELEASE));
+            if (!mRetain || !mRelease) {
+                ALOGE("invalid gralloc1 device");
+                gralloc1_close(mDevice);
+                return false;
+            }
+        } else {
+            mModule = reinterpret_cast<const gralloc_module_t*>(module);
+        }
+
+        return true;
+    }
+
+    void closeGralloc()
+    {
+        if (mDevice) {
+            gralloc1_close(mDevice);
+        }
+    }
+
+    buffer_handle_t cloneBuffer(buffer_handle_t handle)
+    {
+        native_handle_t* clone = native_handle_clone(handle);
+        if (!clone) {
+            ALOGE("failed to clone buffer %p", handle);
+            return nullptr;
+        }
+
+        bool err;
+        if (mDevice) {
+            err = (mRetain(mDevice, clone) != GRALLOC1_ERROR_NONE);
+        } else {
+            err = (mModule->registerBuffer(mModule, clone) != 0);
+        }
+
+        if (err) {
+            ALOGE("failed to retain/register buffer %p", clone);
+            native_handle_close(clone);
+            native_handle_delete(clone);
+            return nullptr;
+        }
+
+        return clone;
+    }
+
+    void releaseBuffer(buffer_handle_t handle)
+    {
+        if (mDevice) {
+            mRelease(mDevice, handle);
+        } else {
+            mModule->unregisterBuffer(mModule, handle);
+            native_handle_close(handle);
+            native_handle_delete(const_cast<native_handle_t*>(handle));
+        }
+    }
+
+    // gralloc1
+    gralloc1_device_t* mDevice;
+    GRALLOC1_PFN_RETAIN mRetain;
+    GRALLOC1_PFN_RELEASE mRelease;
+
+    // gralloc0
+    const gralloc_module_t* mModule;
+#else
+    bool openGralloc() { return true; }
+    void closeGralloc() {}
+    buffer_handle_t cloneBuffer(buffer_handle_t handle) { return handle; }
+    void releaseBuffer(buffer_handle_t) {}
+#endif
+};
+
+HandleImporter sHandleImporter;
+
+} // Anonymous namespace
+
+CameraDeviceSession::CameraDeviceSession(
+    camera3_device_t* device, const sp<ICameraDeviceCallback>& callback) :
+        camera3_callback_ops({&sProcessCaptureResult, &sNotify}),
+        mDevice(device),
+        mCallback(callback) {
+    // For now, we init sHandleImporter but do not cleanup (keep it alive until
+    // HAL process ends)
+    sHandleImporter.initialize();
+
+    mInitFail = initialize();
+}
+
+bool CameraDeviceSession::initialize() {
+    /** Initialize device with callback functions */
+    ATRACE_BEGIN("camera3->initialize");
+    status_t res = mDevice->ops->initialize(mDevice, this);
+    ATRACE_END();
+
+    if (res != OK) {
+        ALOGE("%s: Unable to initialize HAL device: %s (%d)",
+                __FUNCTION__, strerror(-res), res);
+        mDevice->common.close(&mDevice->common);
+        mClosed = true;
+        return true;
+    }
+    return false;
+}
+
+CameraDeviceSession::~CameraDeviceSession() {
+    if (!isClosed()) {
+        ALOGE("CameraDeviceSession deleted before close!");
+        close();
+    }
+}
+
+bool CameraDeviceSession::isClosed() {
+    Mutex::Autolock _l(mStateLock);
+    return mClosed;
+}
+
+Status CameraDeviceSession::initStatus() const {
+    Mutex::Autolock _l(mStateLock);
+    Status status = Status::OK;
+    if (mInitFail) {
+        status = Status::INTERNAL_ERROR;
+    } else if (mDisconnected) {
+        status = Status::CAMERA_DISCONNECTED;
+    } else if (mClosed) {
+        status = Status::INTERNAL_ERROR;
+    }
+    return status;
+}
+
+void CameraDeviceSession::disconnect() {
+    Mutex::Autolock _l(mStateLock);
+    mDisconnected = true;
+    ALOGW("%s: Camera device is disconnected. Closing.", __FUNCTION__);
+    if (!mClosed) {
+        mDevice->common.close(&mDevice->common);
+        mClosed = true;
+    }
+}
+
+void CameraDeviceSession::dumpState(const native_handle_t* fd) {
+    if (!isClosed()) {
+        mDevice->ops->dump(mDevice, fd->data[0]);
+    }
+}
+
+Status CameraDeviceSession::importRequest(
+        const CaptureRequest& request,
+        hidl_vec<buffer_handle_t*>& allBufPtrs,
+        hidl_vec<int>& allFences) {
+    bool hasInputBuf = (request.inputBuffer.streamId != -1 &&
+            request.inputBuffer.buffer.getNativeHandle() != nullptr);
+    size_t numOutputBufs = request.outputBuffers.size();
+    size_t numBufs = numOutputBufs + (hasInputBuf ? 1 : 0);
+    // Validate all I/O buffers
+    hidl_vec<buffer_handle_t> allBufs;
+    allBufs.resize(numBufs);
+    allBufPtrs.resize(numBufs);
+    allFences.resize(numBufs);
+    std::vector<int32_t> streamIds(numBufs);
+
+    for (size_t i = 0; i < numOutputBufs; i++) {
+        allBufs[i] = request.outputBuffers[i].buffer.getNativeHandle();
+        allBufPtrs[i] = &allBufs[i];
+        streamIds[i] = request.outputBuffers[i].streamId;
+    }
+    if (hasInputBuf) {
+        allBufs[numOutputBufs] = request.inputBuffer.buffer.getNativeHandle();
+        allBufPtrs[numOutputBufs] = &allBufs[numOutputBufs];
+        streamIds[numOutputBufs] = request.inputBuffer.streamId;
+    }
+
+    for (size_t i = 0; i < numBufs; i++) {
+        buffer_handle_t buf = allBufs[i];
+        CirculatingBuffers& cbs = mCirculatingBuffers[streamIds[i]];
+        if (cbs.count(buf) == 0) {
+            // Register a newly seen buffer
+            buffer_handle_t importedBuf = buf;
+            sHandleImporter.importBuffer(importedBuf);
+            if (importedBuf == nullptr) {
+                ALOGE("%s: output buffer %zu is invalid!", __FUNCTION__, i);
+                return Status::INTERNAL_ERROR;
+            } else {
+                cbs[buf] = importedBuf;
+            }
+        }
+        allBufPtrs[i] = &cbs[buf];
+    }
+
+    // All buffers are imported. Now validate output buffer acquire fences
+    for (size_t i = 0; i < numOutputBufs; i++) {
+        if (!sHandleImporter.importFence(
+                request.outputBuffers[i].acquireFence, allFences[i])) {
+            ALOGE("%s: output buffer %zu acquire fence is invalid", __FUNCTION__, i);
+            cleanupInflightFences(allFences, i);
+            return Status::INTERNAL_ERROR;
+        }
+    }
+
+    // Validate input buffer acquire fences
+    if (hasInputBuf) {
+        if (!sHandleImporter.importFence(
+                request.inputBuffer.acquireFence, allFences[numOutputBufs])) {
+            ALOGE("%s: input buffer acquire fence is invalid", __FUNCTION__);
+            cleanupInflightFences(allFences, numOutputBufs);
+            return Status::INTERNAL_ERROR;
+        }
+    }
+    return Status::OK;
+}
+
+void CameraDeviceSession::cleanupInflightFences(
+        hidl_vec<int>& allFences, size_t numFences) {
+    for (size_t j = 0; j < numFences; j++) {
+        sHandleImporter.closeFence(allFences[j]);
+    }
+}
+
+// Methods from ::android::hardware::camera::device::V3_2::ICameraDeviceSession follow.
+Return<void> CameraDeviceSession::constructDefaultRequestSettings(
+        RequestTemplate type, constructDefaultRequestSettings_cb _hidl_cb)  {
+    Status status = initStatus();
+    CameraMetadata outMetadata;
+    const camera_metadata_t *rawRequest;
+    if (status == Status::OK) {
+        ATRACE_BEGIN("camera3->construct_default_request_settings");
+        rawRequest = mDevice->ops->construct_default_request_settings(mDevice, (int) type);
+        ATRACE_END();
+        if (rawRequest == nullptr) {
+            ALOGI("%s: template %d is not supported on this camera device",
+                  __FUNCTION__, type);
+            status = Status::ILLEGAL_ARGUMENT;
+        } else {
+            convertToHidl(rawRequest, &outMetadata);
+        }
+    }
+    _hidl_cb(status, outMetadata);
+    return Void();
+}
+
+Return<void> CameraDeviceSession::configureStreams(
+        const StreamConfiguration& requestedConfiguration, configureStreams_cb _hidl_cb)  {
+    Status status = initStatus();
+    HalStreamConfiguration outStreams;
+
+    // hold the inflight lock for entire configureStreams scope since there must not be any
+    // inflight request/results during stream configuration.
+    Mutex::Autolock _l(mInflightLock);
+    if (!mInflightBuffers.empty()) {
+        ALOGE("%s: trying to configureStreams while there are still %zu inflight buffers!",
+                __FUNCTION__, mInflightBuffers.size());
+        _hidl_cb(Status::INTERNAL_ERROR, outStreams);
+        return Void();
+    }
+
+
+
+    if (status == Status::OK) {
+        camera3_stream_configuration_t stream_list;
+        hidl_vec<camera3_stream_t*> streams;
+
+        stream_list.operation_mode = (uint32_t) requestedConfiguration.operationMode;
+        stream_list.num_streams = requestedConfiguration.streams.size();
+        streams.resize(stream_list.num_streams);
+        stream_list.streams = streams.data();
+
+        for (uint32_t i = 0; i < stream_list.num_streams; i++) {
+            int id = requestedConfiguration.streams[i].id;
+
+            if (mStreamMap.count(id) == 0) {
+                Camera3Stream stream;
+                convertFromHidl(requestedConfiguration.streams[i], &stream);
+                mStreamMap[id] = stream;
+                mCirculatingBuffers.emplace(stream.mId, CirculatingBuffers{});
+            } else {
+                // width/height/format must not change, but usage/rotation might need to change
+                if (mStreamMap[id].stream_type !=
+                        (int) requestedConfiguration.streams[i].streamType ||
+                        mStreamMap[id].width != requestedConfiguration.streams[i].width ||
+                        mStreamMap[id].height != requestedConfiguration.streams[i].height ||
+                        mStreamMap[id].format != (int) requestedConfiguration.streams[i].format ||
+                        mStreamMap[id].data_space != (android_dataspace_t)
+                                requestedConfiguration.streams[i].dataSpace) {
+                    ALOGE("%s: stream %d configuration changed!", __FUNCTION__, id);
+                    _hidl_cb(Status::INTERNAL_ERROR, outStreams);
+                    return Void();
+                }
+                mStreamMap[id].rotation = (int) requestedConfiguration.streams[i].rotation;
+                mStreamMap[id].usage = (uint32_t) requestedConfiguration.streams[i].usage;
+            }
+            streams[i] = &mStreamMap[id];
+        }
+
+        ATRACE_BEGIN("camera3->configure_streams");
+        status_t ret = mDevice->ops->configure_streams(mDevice, &stream_list);
+        ATRACE_END();
+
+        // delete unused streams, note we do this after adding new streams to ensure new stream
+        // will not have the same address as deleted stream, and HAL has a chance to reference
+        // the to be deleted stream in configure_streams call
+        for(auto it = mStreamMap.begin(); it != mStreamMap.end();) {
+            int id = it->first;
+            bool found = false;
+            for (const auto& stream : requestedConfiguration.streams) {
+                if (id == stream.id) {
+                    found = true;
+                    break;
+                }
+            }
+            if (!found) {
+                // Unmap all buffers of deleted stream
+                for (auto& pair : mCirculatingBuffers.at(id)) {
+                    sHandleImporter.freeBuffer(pair.second);
+                }
+                mCirculatingBuffers[id].clear();
+                mCirculatingBuffers.erase(id);
+                it = mStreamMap.erase(it);
+            } else {
+                ++it;
+            }
+        }
+
+        if (ret == -EINVAL) {
+            status = Status::ILLEGAL_ARGUMENT;
+        } else if (ret != OK) {
+            status = Status::INTERNAL_ERROR;
+        } else {
+            convertToHidl(stream_list, &outStreams);
+        }
+
+    }
+    _hidl_cb(status, outStreams);
+    return Void();
+}
+
+Return<Status> CameraDeviceSession::processCaptureRequest(const CaptureRequest& request)  {
+    Status status = initStatus();
+    if (status != Status::OK) {
+        ALOGE("%s: camera init failed or disconnected", __FUNCTION__);
+        return status;
+    }
+
+    camera3_capture_request_t halRequest;
+    halRequest.frame_number = request.frameNumber;
+    bool converted = convertFromHidl(request.settings, &halRequest.settings);
+    if (!converted) {
+        ALOGE("%s: capture request settings metadata is corrupt!", __FUNCTION__);
+        return Status::INTERNAL_ERROR;
+    }
+
+    hidl_vec<buffer_handle_t*> allBufPtrs;
+    hidl_vec<int> allFences;
+    bool hasInputBuf = (request.inputBuffer.streamId != -1 &&
+            request.inputBuffer.buffer.getNativeHandle() != nullptr);
+    size_t numOutputBufs = request.outputBuffers.size();
+    size_t numBufs = numOutputBufs + (hasInputBuf ? 1 : 0);
+    status = importRequest(request, allBufPtrs, allFences);
+    if (status != Status::OK) {
+        return status;
+    }
+
+    hidl_vec<camera3_stream_buffer_t> outHalBufs;
+    outHalBufs.resize(numOutputBufs);
+    {
+        Mutex::Autolock _l(mInflightLock);
+        if (hasInputBuf) {
+            auto key = std::make_pair(request.inputBuffer.streamId, request.frameNumber);
+            auto& bufCache = mInflightBuffers[key] = camera3_stream_buffer_t{};
+            convertFromHidl(
+                    allBufPtrs[numOutputBufs], request.inputBuffer.status,
+                    &mStreamMap[request.inputBuffer.streamId], allFences[numOutputBufs],
+                    &bufCache);
+            halRequest.input_buffer = &bufCache;
+        } else {
+            halRequest.input_buffer = nullptr;
+        }
+
+        halRequest.num_output_buffers = numOutputBufs;
+        for (size_t i = 0; i < numOutputBufs; i++) {
+            auto key = std::make_pair(request.outputBuffers[i].streamId, request.frameNumber);
+            auto& bufCache = mInflightBuffers[key] = camera3_stream_buffer_t{};
+            convertFromHidl(
+                    allBufPtrs[i], request.outputBuffers[i].status,
+                    &mStreamMap[request.outputBuffers[i].streamId], allFences[i],
+                    &bufCache);
+            outHalBufs[i] = bufCache;
+        }
+        halRequest.output_buffers = outHalBufs.data();
+    }
+
+    ATRACE_ASYNC_BEGIN("frame capture", request.frameNumber);
+    ATRACE_BEGIN("camera3->process_capture_request");
+    status_t ret = mDevice->ops->process_capture_request(mDevice, &halRequest);
+    ATRACE_END();
+    if (ret != OK) {
+        Mutex::Autolock _l(mInflightLock);
+        ALOGE("%s: HAL process_capture_request call failed!", __FUNCTION__);
+
+        cleanupInflightFences(allFences, numBufs);
+        if (hasInputBuf) {
+            auto key = std::make_pair(request.inputBuffer.streamId, request.frameNumber);
+            mInflightBuffers.erase(key);
+        }
+        for (size_t i = 0; i < numOutputBufs; i++) {
+            auto key = std::make_pair(request.outputBuffers[i].streamId, request.frameNumber);
+            mInflightBuffers.erase(key);
+        }
+        return Status::INTERNAL_ERROR;
+    }
+
+    return Status::OK;
+}
+
+Return<Status> CameraDeviceSession::flush()  {
+    Status status = initStatus();
+    if (status == Status::OK) {
+        // Flush is always supported on device 3.1 or later
+        status_t ret = mDevice->ops->flush(mDevice);
+        if (ret != OK) {
+            status = Status::INTERNAL_ERROR;
+        }
+    }
+    return status;
+}
+
+Return<void> CameraDeviceSession::close()  {
+    Mutex::Autolock _l(mStateLock);
+    if (!mClosed) {
+        {
+            Mutex::Autolock _l(mInflightLock);
+            if (!mInflightBuffers.empty()) {
+                ALOGE("%s: trying to close while there are still %zu inflight buffers!",
+                        __FUNCTION__, mInflightBuffers.size());
+            }
+        }
+
+        ATRACE_BEGIN("camera3->close");
+        mDevice->common.close(&mDevice->common);
+        ATRACE_END();
+
+        // free all imported buffers
+        for(auto& pair : mCirculatingBuffers) {
+            CirculatingBuffers& buffers = pair.second;
+            for (auto& p2 : buffers) {
+                sHandleImporter.freeBuffer(p2.second);
+            }
+        }
+
+        mClosed = true;
+    }
+    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));
+
+    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);
+    Status status = Status::OK;
+    {
+        Mutex::Autolock _l(d->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) {
+                ALOGE("%s: input buffer for stream %d frame %d is not inflight!",
+                        __FUNCTION__, streamId, frameNumber);
+                return;
+            }
+        }
+
+        for (size_t i = 0; i < numOutputBufs; i++) {
+            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) {
+                ALOGE("%s: output buffer for stream %d frame %d is not inflight!",
+                        __FUNCTION__, streamId, frameNumber);
+                return;
+            }
+        }
+    }
+    // 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;
+    hidl_vec<native_handle_t*> releaseFences;
+    releaseFences.resize(numBufs);
+    result.frameNumber = frameNumber;
+    result.partialResult = hal_result->partial_result;
+    convertToHidl(hal_result->result, &result.result);
+    if (hasInputBuf) {
+        result.inputBuffer.streamId =
+                static_cast<Camera3Stream*>(hal_result->input_buffer->stream)->mId;
+        result.inputBuffer.buffer = nullptr;
+        result.inputBuffer.status = (BufferStatus) hal_result->input_buffer->status;
+        // skip acquire fence since it's no use to camera service
+        if (hal_result->input_buffer->release_fence != -1) {
+            releaseFences[numOutputBufs] = native_handle_create(/*numFds*/1, /*numInts*/0);
+            releaseFences[numOutputBufs]->data[0] = hal_result->input_buffer->release_fence;
+            result.inputBuffer.releaseFence = releaseFences[numOutputBufs];
+        } else {
+            releaseFences[numOutputBufs] = nullptr;
+        }
+    } else {
+        result.inputBuffer.streamId = -1;
+    }
+
+    result.outputBuffers.resize(numOutputBufs);
+    for (size_t i = 0; i < numOutputBufs; i++) {
+        result.outputBuffers[i].streamId =
+                static_cast<Camera3Stream*>(hal_result->output_buffers[i].stream)->mId;
+        result.outputBuffers[i].buffer = nullptr;
+        result.outputBuffers[i].status = (BufferStatus) hal_result->output_buffers[i].status;
+        // skip acquire fence since it's of no use to camera service
+        if (hal_result->output_buffers[i].release_fence != -1) {
+            releaseFences[i] = native_handle_create(/*numFds*/1, /*numInts*/0);
+            releaseFences[i]->data[0] = hal_result->output_buffers[i].release_fence;
+            result.outputBuffers[i].releaseFence = releaseFences[i];
+        } else {
+            releaseFences[i] = nullptr;
+        }
+    }
+
+    // Free inflight record/fences.
+    // Do this before call back to camera service because camera service might jump to
+    // configure_streams right after the processCaptureResult call so we need to finish
+    // updating inflight queues first
+    {
+        Mutex::Autolock _l(d->mInflightLock);
+        if (hasInputBuf) {
+            int streamId = static_cast<Camera3Stream*>(hal_result->input_buffer->stream)->mId;
+            auto key = std::make_pair(streamId, frameNumber);
+            sHandleImporter.closeFence(d->mInflightBuffers[key].acquire_fence);
+            d->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);
+            sHandleImporter.closeFence(d->mInflightBuffers[key].acquire_fence);
+            d->mInflightBuffers.erase(key);
+        }
+
+        if (d->mInflightBuffers.empty()) {
+            ALOGV("%s: inflight buffer queue is now empty!", __FUNCTION__);
+        }
+    }
+
+    d->mCallback->processCaptureResult(result);
+
+    for (size_t i = 0; i < releaseFences.size(); i++) {
+        // We don't close the FD here as HAL needs to signal it later.
+        native_handle_delete(releaseFences[i]);
+    }
+}
+
+void CameraDeviceSession::sNotify(
+        const camera3_callback_ops *cb,
+        const camera3_notify_msg *msg) {
+    CameraDeviceSession *d =
+            const_cast<CameraDeviceSession*>(static_cast<const CameraDeviceSession*>(cb));
+    NotifyMsg hidlMsg;
+    convertToHidl(msg, &hidlMsg);
+    if (hidlMsg.type == (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;
+    }
+    d->mCallback->notify(hidlMsg);
+}
+
+} // namespace implementation
+}  // namespace V3_2
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
diff --git a/camera/device/3.2/default/CameraDeviceSession.h b/camera/device/3.2/default/CameraDeviceSession.h
new file mode 100644
index 0000000..498617e
--- /dev/null
+++ b/camera/device/3.2/default/CameraDeviceSession.h
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2016 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_CAMERA_DEVICE_V3_2_CAMERADEVICE3SESSION_H
+#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_2_CAMERADEVICE3SESSION_H
+
+#include <unordered_map>
+#include "hardware/camera_common.h"
+#include "hardware/camera3.h"
+#include "utils/Mutex.h"
+#include <android/hardware/camera/device/3.2/ICameraDevice.h>
+#include <android/hardware/camera/device/3.2/ICameraDeviceSession.h>
+#include <hidl/Status.h>
+#include <hidl/MQDescriptor.h>
+#include <include/convert.h>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_2 {
+namespace implementation {
+
+using ::android::hardware::camera::device::V3_2::CaptureRequest;
+using ::android::hardware::camera::device::V3_2::HalStreamConfiguration;
+using ::android::hardware::camera::device::V3_2::StreamConfiguration;
+using ::android::hardware::camera::device::V3_2::ICameraDeviceSession;
+using ::android::hardware::camera::common::V1_0::Status;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+using ::android::Mutex;
+
+/**
+ * Function pointer types with C calling convention to
+ * use for HAL callback functions.
+ */
+extern "C" {
+    typedef void (callbacks_process_capture_result_t)(
+        const struct camera3_callback_ops *,
+        const camera3_capture_result_t *);
+
+    typedef void (callbacks_notify_t)(
+        const struct camera3_callback_ops *,
+        const camera3_notify_msg_t *);
+}
+
+struct CameraDeviceSession : public ICameraDeviceSession, private camera3_callback_ops  {
+
+    CameraDeviceSession(camera3_device_t*, const sp<ICameraDeviceCallback>&);
+    ~CameraDeviceSession();
+    // Call by CameraDevice to dump active device states
+    void dumpState(const native_handle_t* fd);
+    // Caller must use this method to check if CameraDeviceSession ctor failed
+    bool isInitFailed() { return mInitFail; }
+    // Used by CameraDevice to signal external camera disconnected
+    void disconnect();
+    bool isClosed();
+
+    // Methods from ::android::hardware::camera::device::V3_2::ICameraDeviceSession follow.
+    Return<void> constructDefaultRequestSettings(RequestTemplate type, constructDefaultRequestSettings_cb _hidl_cb) override;
+    Return<void> configureStreams(const StreamConfiguration& requestedConfiguration, configureStreams_cb _hidl_cb) override;
+    Return<Status> processCaptureRequest(const CaptureRequest& request) override;
+    Return<Status> flush() override;
+    Return<void> close() override;
+
+private:
+    // protecting mClosed/mDisconnected/mInitFail
+    mutable Mutex mStateLock;
+    // device is closed either
+    //    - closed by user
+    //    - init failed
+    //    - camera disconnected
+    bool mClosed = false;
+
+    // Set by CameraDevice (when external camera is disconnected)
+    bool mDisconnected = false;
+
+    camera3_device_t* mDevice;
+    const sp<ICameraDeviceCallback> mCallback;
+    // Stream ID -> Camera3Stream cache
+    std::map<int, Camera3Stream> mStreamMap;
+
+    mutable Mutex mInflightLock; // protecting mInflightBuffers and mCirculatingBuffers
+    // (streamID, frameNumber) -> inflight buffer cache
+    std::map<std::pair<int, uint32_t>, camera3_stream_buffer_t>  mInflightBuffers;
+
+    struct BufferHasher {
+        size_t operator()(const buffer_handle_t& buf) const {
+            if (buf == nullptr)
+                return 0;
+
+            size_t result = 1;
+            result = 31 * result + buf->numFds;
+            result = 31 * result + buf->numInts;
+            int length = buf->numFds + buf->numInts;
+            for (int i = 0; i < length; i++) {
+                result = 31 * result + buf->data[i];
+            }
+            return result;
+        }
+    };
+
+    struct BufferComparator {
+        bool operator()(const buffer_handle_t& buf1, const buffer_handle_t& buf2) const {
+            if (buf1->numFds == buf2->numFds && buf1->numInts == buf2->numInts) {
+                int length = buf1->numFds + buf1->numInts;
+                for (int i = 0; i < length; i++) {
+                    if (buf1->data[i] != buf2->data[i]) {
+                        return false;
+                    }
+                }
+                return true;
+            }
+            return false;
+        }
+    };
+
+    // buffers currently ciculating between HAL and camera service
+    // key: buffer_handle_t sent via HIDL interface
+    // value: imported buffer_handle_t
+    // Buffer will be imported during process_capture_request and will be freed
+    // when the its stream is deleted or camera device session is closed
+    typedef std::unordered_map<buffer_handle_t, buffer_handle_t,
+            BufferHasher, BufferComparator> CirculatingBuffers;
+    // Stream ID -> circulating buffers map
+    std::map<int, CirculatingBuffers> mCirculatingBuffers;
+
+    bool mInitFail;
+    bool initialize();
+
+    Status initStatus() const;
+
+    // Validate and import request's input buffer and acquire fence
+    Status importRequest(
+            const CaptureRequest& request,
+            hidl_vec<buffer_handle_t*>& allBufPtrs,
+            hidl_vec<int>& allFences);
+
+    static void cleanupInflightFences(
+            hidl_vec<int>& allFences, size_t numFences);
+
+    /**
+     * Static callback forwarding methods from HAL to instance
+     */
+    static callbacks_process_capture_result_t sProcessCaptureResult;
+    static callbacks_notify_t sNotify;
+};
+
+}  // namespace implementation
+}  // namespace V3_2
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_CAMERA_DEVICE_V3_2_CAMERADEVICE3SESSION_H
diff --git a/camera/device/3.2/default/convert.cpp b/camera/device/3.2/default/convert.cpp
new file mode 100644
index 0000000..35676df
--- /dev/null
+++ b/camera/device/3.2/default/convert.cpp
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2016 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.camera.device@3.2-convert-impl"
+#include <android/log.h>
+
+#include "include/convert.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_2 {
+namespace implementation {
+
+using ::android::hardware::graphics::common::V1_0::Dataspace;
+using ::android::hardware::graphics::common::V1_0::PixelFormat;
+using ::android::hardware::camera::device::V3_2::ConsumerUsageFlags;
+using ::android::hardware::camera::device::V3_2::ProducerUsageFlags;
+
+bool convertFromHidl(const CameraMetadata &src, const camera_metadata_t** dst) {
+    if (src.size() == 0) {
+        // Special case for null metadata
+        *dst = nullptr;
+        return true;
+    }
+
+    const uint8_t* data = src.data();
+    // sanity check the size of CameraMetadata match underlying camera_metadata_t
+    if (get_camera_metadata_size((camera_metadata_t*)data) != src.size()) {
+        ALOGE("%s: input CameraMetadata is corrupt!", __FUNCTION__);
+        return false;
+    }
+    *dst = (camera_metadata_t*) data;
+    return true;
+}
+
+// Note: existing data in dst will be gone. Caller still owns the memory of src
+void convertToHidl(const camera_metadata_t *src, CameraMetadata* dst) {
+    if (src == nullptr) {
+        return;
+    }
+    size_t size = get_camera_metadata_size(src);
+    dst->setToExternal((uint8_t *) src, size);
+    return;
+}
+
+void convertFromHidl(const Stream &src, Camera3Stream* dst) {
+    dst->mId = src.id;
+    dst->stream_type = (int) src.streamType;
+    dst->width = src.width;
+    dst->height = src.height;
+    dst->format = (int) src.format;
+    dst->data_space = (android_dataspace_t) src.dataSpace;
+    dst->rotation = (int) src.rotation;
+    dst->usage = (uint32_t) src.usage;
+    // Fields to be filled by HAL (max_buffers, priv) are initialized to 0
+    dst->max_buffers = 0;
+    dst->priv = 0;
+    return;
+}
+
+void convertToHidl(const Camera3Stream* src, HalStream* dst) {
+    dst->id = src->mId;
+    dst->overrideFormat = (PixelFormat) src->format;
+    dst->maxBuffers = src->max_buffers;
+    if (src->stream_type == CAMERA3_STREAM_OUTPUT) {
+        dst->consumerUsage = (ConsumerUsageFlags) 0;
+        dst->producerUsage = (ProducerUsageFlags) src->usage;
+    } else if (src->stream_type == CAMERA3_STREAM_INPUT) {
+        dst->producerUsage = (ProducerUsageFlags) 0;
+        dst->consumerUsage = (ConsumerUsageFlags) src->usage;
+    } else {
+        //Should not reach here per current HIDL spec, but we might end up adding
+        // bi-directional stream to HIDL.
+        ALOGW("%s: Stream type %d is not currently supported!",
+                __FUNCTION__, src->stream_type);
+    }
+}
+
+void convertToHidl(const camera3_stream_configuration_t& src, HalStreamConfiguration* dst) {
+    dst->streams.resize(src.num_streams);
+    for (uint32_t i = 0; i < src.num_streams; i++) {
+        convertToHidl(static_cast<Camera3Stream*>(src.streams[i]), &dst->streams[i]);
+    }
+    return;
+}
+
+void convertFromHidl(
+        buffer_handle_t* bufPtr, BufferStatus status, camera3_stream_t* stream, int acquireFence,
+        camera3_stream_buffer_t* dst) {
+    dst->stream = stream;
+    dst->buffer = bufPtr;
+    dst->status = (int) status;
+    dst->acquire_fence = acquireFence;
+    dst->release_fence = -1; // meant for HAL to fill in
+}
+
+void convertToHidl(const camera3_notify_msg* src, NotifyMsg* dst) {
+    dst->type = (MsgType) src->type;
+    switch (src->type) {
+        case CAMERA3_MSG_ERROR:
+            {
+                // The camera3_stream_t* must be the same as what wrapper HAL passed to conventional
+                // HAL, or the ID lookup will return garbage. Caller should validate the ID here is
+                // indeed one of active stream IDs
+                Camera3Stream* stream = static_cast<Camera3Stream*>(
+                        src->message.error.error_stream);
+                dst->msg.error.frameNumber = src->message.error.frame_number;
+                dst->msg.error.errorStreamId = (stream != nullptr) ? stream->mId : -1;
+                dst->msg.error.errorCode = (ErrorCode) src->message.error.error_code;
+            }
+            break;
+        case CAMERA3_MSG_SHUTTER:
+            dst->msg.shutter.frameNumber = src->message.shutter.frame_number;
+            dst->msg.shutter.timestamp = src->message.shutter.timestamp;
+            break;
+        default:
+            ALOGE("%s: HIDL type converion failed. Unknown msg type 0x%x",
+                    __FUNCTION__, src->type);
+    }
+    return;
+}
+
+}  // namespace implementation
+}  // namespace V3_2
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
diff --git a/camera/device/3.2/default/include/convert.h b/camera/device/3.2/default/include/convert.h
new file mode 100644
index 0000000..96891f0
--- /dev/null
+++ b/camera/device/3.2/default/include/convert.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2016 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 HARDWARE_INTERFACES_CAMERA_DEVICE_V3_2_DEFAULT_INCLUDE_CONVERT_H_
+
+#define HARDWARE_INTERFACES_CAMERA_DEVICE_V3_2_DEFAULT_INCLUDE_CONVERT_H_
+
+#include <set>
+
+
+#include <android/hardware/graphics/common/1.0/types.h>
+#include <android/hardware/camera/device/3.2/types.h>
+#include "hardware/camera3.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_2 {
+namespace implementation {
+
+// The camera3_stream_t sent to conventional HAL. Added mId fields to enable stream ID lookup
+// fromt a downcasted camera3_stream
+struct Camera3Stream : public camera3_stream {
+    int mId;
+};
+
+// *dst will point to the data owned by src, but src still owns the data after this call returns.
+bool convertFromHidl(const CameraMetadata &src, const camera_metadata_t** dst);
+void convertToHidl(const camera_metadata_t* src, CameraMetadata* dst);
+
+void convertFromHidl(const Stream &src, Camera3Stream* dst);
+void convertToHidl(const Camera3Stream* src, HalStream* dst);
+
+void convertFromHidl(
+        buffer_handle_t*, BufferStatus, camera3_stream_t*, int acquireFence, // inputs
+        camera3_stream_buffer_t* dst);
+
+void convertToHidl(const camera3_stream_configuration_t& src, HalStreamConfiguration* dst);
+
+// The camera3_stream_t* in src must be the same as what wrapper HAL passed to conventional
+// HAL, or the ID lookup will return garbage. Caller should validate the ID in ErrorMsg is
+// indeed one of active stream IDs
+void convertToHidl(const camera3_notify_msg* src, NotifyMsg* dst);
+
+}  // namespace implementation
+}  // namespace V3_2
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
+
+#endif  // HARDWARE_INTERFACES_CAMERA_DEVICE_V3_2_DEFAULT_INCLUDE_CONVERT_H_
diff --git a/camera/device/3.2/types.hal b/camera/device/3.2/types.hal
index ed6ef7d..1e0924c 100644
--- a/camera/device/3.2/types.hal
+++ b/camera/device/3.2/types.hal
@@ -403,12 +403,23 @@
  */
 struct StreamBuffer {
     /**
-     * The ID of the stream this buffer is associated with
+     * The ID of the stream this buffer is associated with. -1 indicates an
+     * invalid (empty) StreamBuffer, in which case buffer must also point to
+     * null.
      */
     int32_t streamId;
 
     /**
-     * The graphics buffer handle to the buffer
+     * The graphics buffer handle to the buffer.
+     *
+     * For StreamBuffers sent to the HAL in a CaptureRequest, this must be a
+     * valid handle to a graphics buffer, with dimensions and format matching
+     * that of the stream.
+     *
+     * For StreamBuffers returned in a CaptureResult, this must be null, since
+     * the handle to the buffer is already known to the client (since the client
+     * sent it in the matching CaptureRequest), and the handle can be identified
+     * by the combination of frame number and stream ID.
      */
     handle buffer;
 
@@ -424,44 +435,34 @@
      * The acquire sync fence for this buffer. The HAL must wait on this fence
      * fd before attempting to read from or write to this buffer.
      *
-     * The framework may be set to -1 to indicate that no waiting is necessary
-     * for this buffer.
+     * In a buffer included in a CaptureRequest, the client may set this to null
+     * to indicate that no waiting is necessary for this buffer.
      *
-     * When the HAL returns an output buffer to the framework with
-     * processCaptureResult(), the acquireFence must be set to -1. If the HAL
-     * never waits on the acquireFence due to an error in filling a buffer,
-     * when calling processCaptureResult() the HAL must set the releaseFence
-     * of the buffer to be the acquireFence passed to it by the framework. This
-     * allows the framework to wait on the fence before reusing the buffer.
-     *
-     * For input buffers, the HAL must not change the acquireFence field during
-     * the processCaptureRequest() call.
-     *
-     * When the HAL returns an input buffer to the framework with
-     * processCaptureResult(), the acquireFence must be set to -1. If the HAL
-     * never waits on input buffer acquire fence due to an error, the sync
-     * fences must be handled similarly to the way they are handled for output
-     * buffers.
+     * When the HAL returns an input or output buffer to the framework with
+     * processCaptureResult(), the acquireFence must be set to null. If the HAL
+     * never waits on the acquireFence due to an error in filling or reading a
+     * buffer, when calling processCaptureResult() the HAL must set the
+     * releaseFence of the buffer to be the acquireFence passed to it by the
+     * client. This allows the client to wait on the fence before reusing the
+     * buffer.
      */
     handle acquireFence;
 
     /**
-     * The release sync fence for this buffer. The HAL must set this fence when
-     * returning buffers to the framework, or write -1 to indicate that no
-     * waiting is required for this buffer.
+     * The release sync fence for this buffer. The HAL must set this to a valid
+     * fence fd when returning the input buffer or output buffers to the client
+     * in a CaptureResult, or set it to null to indicate that no waiting is
+     * required for this buffer.
      *
-     * For the output buffers, the fences must be set in the outputBuffers
-     * array passed to processCaptureResult().
-     *
-     * For the input buffer, the fences must be set in the inputBuffer
-     * passed to processCaptureResult().
+     * The client must set this to be null for all buffers included in a
+     * processCaptureRequest call.
      *
      * After signaling the releaseFence for this buffer, the HAL
      * must not make any further attempts to access this buffer as the
-     * ownership has been fully transferred back to the framework.
+     * ownership has been fully transferred back to the client.
      *
-     * If a fence of -1 was specified then the ownership of this buffer
-     * is transferred back immediately upon the call of processCaptureResult.
+     * If this is null, then the ownership of this buffer is transferred back
+     * immediately upon the call of processCaptureResult.
      */
     handle releaseFence;
 
@@ -606,7 +607,7 @@
 };
 
 /**
- * MotifyMsg:
+ * NotifyMsg:
  *
  * The message structure sent to ICameraDevice3Callback::notify()
  */
@@ -722,13 +723,13 @@
     /**
      * The input stream buffer to use for this request, if any.
      *
+     * An invalid inputBuffer is signified by a null inputBuffer::buffer, in
+     * which case the value of all other members of inputBuffer must be ignored.
+     *
      * If inputBuffer is invalid, then the request is for a new capture from the
      * imager. If inputBuffer is valid, the request is for reprocessing the
-     * image contained in inputBuffer.
-     *
-     * In the latter case, the HAL must set the releaseFence of the
-     * inputBuffer to a valid sync fence, or to -1 if the HAL does not support
-     * sync, before processCaptureRequest() returns.
+     * image contained in inputBuffer, and the HAL must release the inputBuffer
+     * back to the client in a subsequent processCaptureResult call.
      *
      * The HAL is required to wait on the acquire sync fence of the input buffer
      * before accessing it.
@@ -741,9 +742,8 @@
      * data from this capture/reprocess. The HAL must wait on the acquire fences
      * of each stream buffer before writing to them.
      *
-     * The HAL takes ownership of the actual buffer_handle_t entries in
-     * outputBuffers; the framework must not access them until they are
-     * returned in a CaptureResult.
+     * The HAL takes ownership of the handles in outputBuffers; the client
+     * must not access them until they are returned in a CaptureResult.
      *
      * Any or all of the buffers included here may be brand new in this
      * request (having never before seen by the HAL).
@@ -823,10 +823,15 @@
     CameraMetadata result;
 
     /**
-     * The handles for the output stream buffers for this capture. They may not
-     * yet be filled at the time the HAL calls processCaptureResult(); the
-     * framework must wait on the release sync fences provided by the HAL before
-     * reading the buffers.
+     * The completed output stream buffers for this capture.
+     *
+     * They may not yet be filled at the time the HAL calls
+     * processCaptureResult(); the framework must wait on the release sync
+     * fences provided by the HAL before reading the buffers.
+     *
+     * The StreamBuffer::buffer handle must be null for all returned buffers;
+     * the client must cache the handle and look it up via the combination of
+     * frame number and stream ID.
      *
      * The number of output buffers returned must be less than or equal to the
      * matching capture request's count. If this is less than the buffer count
@@ -836,7 +841,7 @@
      * valid result metadata or an input buffer is returned in this result.
      *
      * The HAL must set the stream buffer's release sync fence to a valid sync
-     * fd, or to -1 if the buffer has already been filled.
+     * fd, or to null if the buffer has already been filled.
      *
      * If the HAL encounters an error while processing the buffer, and the
      * buffer is not filled, the buffer's status field must be set to ERROR. If
@@ -844,7 +849,7 @@
      * the acquire fence must be copied into the release fence, to allow the
      * framework to wait on the fence before reusing the buffer.
      *
-     * The acquire fence must be set to -1 for all output buffers.
+     * The acquire fence must be set to null for all output buffers.
      *
      * This vector may be empty; if so, at least one other processCaptureResult
      * call must be made (or have been made) by the HAL to provide the filled
@@ -854,8 +859,8 @@
      * all previous frames' buffers for that corresponding stream must have been
      * already delivered (the fences need not have yet been signaled).
      *
-     * Gralloc buffers for a frame may be sent to framework before the
-     * corresponding SHUTTER-notify.
+     * Buffers for a frame may be sent to framework before the corresponding
+     * SHUTTER-notify call is made by the HAL.
      *
      * Performance considerations:
      *
@@ -867,10 +872,11 @@
     vec<StreamBuffer> outputBuffers;
 
     /**
-     * The handle for the input stream buffer for this capture. It may not
-     * yet be consumed at the time the HAL calls processCaptureResult(); the
-     * framework must wait on the release sync fence provided by the HAL before
-     * reusing the buffer.
+     * The handle for the input stream buffer for this capture, if any.
+     *
+     * It may not yet be consumed at the time the HAL calls
+     * processCaptureResult(); the framework must wait on the release sync fence
+     * provided by the HAL before reusing the buffer.
      *
      * The HAL must handle the sync fences the same way they are done for
      * outputBuffers.
diff --git a/camera/provider/2.4/ICameraProvider.hal b/camera/provider/2.4/ICameraProvider.hal
index 564167b..3015b7d 100644
--- a/camera/provider/2.4/ICameraProvider.hal
+++ b/camera/provider/2.4/ICameraProvider.hal
@@ -120,6 +120,30 @@
             generates (Status status, vec<string> cameraDeviceNames);
 
     /**
+     * isSetTorchModeSupported:
+     *
+     * Returns if the camera devices known to this camera provider support
+     * setTorchMode API or not. If the provider does not support setTorchMode
+     * API, calling to setTorchMode will return METHOD_NOT_SUPPORTED.
+     *
+     * Note that not every camera device has a flash unit, so even this API
+     * returns true, setTorchMode call might still fail due to the camera device
+     * does not have a flash unit. In such case, the returned status will be
+     * OPERATION_NOT_SUPPORTED.
+     *
+     * @return status Status code for the operation, one of:
+     *     OK:
+     *         On a succesful call
+     *     INTERNAL_ERROR:
+     *         Torch API support cannot be queried. This may be due to
+     *         a failure to initialize the camera subsystem, for example.
+     * @return support Whether the camera devices known to this provider
+     *     supports setTorchMode API or not.
+     *
+     */
+    isSetTorchModeSupported() generates (Status status, bool support);
+
+    /**
      * getCameraDeviceInterface_VN_x:
      *
      * Return a android.hardware.camera.device@N.x/ICameraDevice interface for
diff --git a/camera/provider/2.4/default/Android.bp b/camera/provider/2.4/default/Android.bp
new file mode 100644
index 0000000..f28c9cd
--- /dev/null
+++ b/camera/provider/2.4/default/Android.bp
@@ -0,0 +1,23 @@
+cc_library_shared {
+    name: "android.hardware.camera.provider@2.4-impl",
+    relative_install_path: "hw",
+    srcs: ["CameraProvider.cpp"],
+    shared_libs: [
+        "libhidlbase",
+        "libhidltransport",
+        "libhwbinder",
+        "libutils",
+        "libcutils",
+        "android.hardware.camera.device@1.0",
+        "android.hardware.camera.device@3.2",
+        "android.hardware.camera.device@3.2-impl",
+        "android.hardware.camera.provider@2.4",
+        "android.hardware.camera.common@1.0",
+        "liblog",
+        "libhardware",
+        "libcamera_metadata"
+    ],
+    static_libs: [
+        "android.hardware.camera.common@1.0-helper"
+    ]
+}
diff --git a/camera/provider/2.4/default/CameraProvider.cpp b/camera/provider/2.4/default/CameraProvider.cpp
new file mode 100644
index 0000000..9617d8d
--- /dev/null
+++ b/camera/provider/2.4/default/CameraProvider.cpp
@@ -0,0 +1,411 @@
+/*
+ * Copyright (C) 2016 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 "CamProvider@2.4-impl"
+#include <android/log.h>
+
+#include <regex>
+
+#include "CameraProvider.h"
+#include "CameraDevice.h"
+#include <string.h>
+#include <utils/Trace.h>
+
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace provider {
+namespace V2_4 {
+namespace implementation {
+
+namespace {
+const char *kLegacyProviderName = "legacy/0";
+// "device@<version>/legacy/<id>"
+const std::regex kDeviceNameRE("device@([0-9]+\\.[0-9]+)/legacy/(.+)");
+const char *kHAL3_2 = "3.2";
+const char *kHAL1_0 = "1.0";
+const int kMaxCameraDeviceNameLen = 128;
+const int kMaxCameraIdLen = 16;
+
+} // anonymous namespace
+
+using ::android::hardware::camera::common::V1_0::CameraMetadataType;
+using ::android::hardware::camera::common::V1_0::Status;
+
+/**
+ * static callback forwarding methods from HAL to instance
+ */
+void CameraProvider::sCameraDeviceStatusChange(
+        const struct camera_module_callbacks* callbacks,
+        int camera_id,
+        int new_status) {
+    ALOGI("%s++", __FUNCTION__);
+    sp<CameraProvider> cp = const_cast<CameraProvider*>(
+            static_cast<const CameraProvider*>(callbacks));
+
+    if (cp == nullptr) {
+        ALOGE("%s: callback ops is null", __FUNCTION__);
+        return;
+    }
+
+    ALOGI("%s resolved provider %p", __FUNCTION__, cp.get());
+
+    Mutex::Autolock _l(cp->mCbLock);
+    char cameraId[kMaxCameraIdLen];
+    snprintf(cameraId, sizeof(cameraId), "%d", camera_id);
+    std::string cameraIdStr(cameraId);
+    cp->mCameraStatusMap[cameraIdStr] = (camera_device_status_t) new_status;
+    if (cp->mCallbacks != nullptr) {
+        CameraDeviceStatus status = (CameraDeviceStatus) new_status;
+        for (auto const& deviceNamePair : cp->mCameraDeviceNames) {
+            if (cameraIdStr.compare(deviceNamePair.first) == 0) {
+                cp->mCallbacks->cameraDeviceStatusChange(
+                        deviceNamePair.second, status);
+            }
+        }
+    }
+    ALOGI("%s--", __FUNCTION__);
+}
+
+void CameraProvider::sTorchModeStatusChange(
+        const struct camera_module_callbacks* callbacks,
+        const char* camera_id,
+        int new_status) {
+    ALOGI("%s++", __FUNCTION__);
+    sp<CameraProvider> cp = const_cast<CameraProvider*>(
+            static_cast<const CameraProvider*>(callbacks));
+
+    if (cp == nullptr) {
+        ALOGE("%s: callback ops is null", __FUNCTION__);
+        return;
+    }
+
+    ALOGI("%s resolved provider %p", __FUNCTION__, cp.get());
+
+    Mutex::Autolock _l(cp->mCbLock);
+    if (cp->mCallbacks != nullptr) {
+        std::string cameraIdStr(camera_id);
+        TorchModeStatus status = (TorchModeStatus) new_status;
+        for (auto const& deviceNamePair : cp->mCameraDeviceNames) {
+            if (cameraIdStr.compare(deviceNamePair.first) == 0) {
+                cp->mCallbacks->torchModeStatusChange(
+                        deviceNamePair.second, status);
+            }
+        }
+    }
+    ALOGI("%s--", __FUNCTION__);
+}
+
+Status CameraProvider::getHidlStatus(int status) {
+    switch (status) {
+        case 0: return Status::OK;
+        case -ENODEV: return Status::INTERNAL_ERROR;
+        case -EINVAL: return Status::ILLEGAL_ARGUMENT;
+        default:
+            ALOGE("%s: unknown HAL status code %d", __FUNCTION__, status);
+            return Status::INTERNAL_ERROR;
+    }
+}
+
+bool CameraProvider::matchDeviceName(const hidl_string& deviceName, std::smatch& sm) {
+    std::string deviceNameStd(deviceName.c_str());
+    return std::regex_match(deviceNameStd, sm, kDeviceNameRE);
+}
+
+std::string CameraProvider::getLegacyCameraId(const hidl_string& deviceName) {
+    std::smatch sm;
+    bool match = matchDeviceName(deviceName, sm);
+    if (!match) {
+        return std::string("");
+    }
+    return sm[2];
+}
+
+int CameraProvider::getCameraDeviceVersion(const hidl_string& deviceName) {
+    std::smatch sm;
+    bool match = matchDeviceName(deviceName, sm);
+    if (!match) {
+        return -1;
+    }
+    if (sm[1].compare(kHAL3_2) == 0) {
+        // maybe switched to 3.4 or define the hidl version enum later
+        return CAMERA_DEVICE_API_VERSION_3_2;
+    } else if (sm[1].compare(kHAL1_0) == 0) {
+        return CAMERA_DEVICE_API_VERSION_1_0;
+    }
+    return 0;
+}
+
+std::string CameraProvider::getHidlDeviceName(
+        std::string cameraId, int deviceVersion) {
+    // Maybe consider create a version check method and SortedVec to speed up?
+    if (deviceVersion != CAMERA_DEVICE_API_VERSION_1_0 &&
+            deviceVersion != CAMERA_DEVICE_API_VERSION_3_2 &&
+            deviceVersion != CAMERA_DEVICE_API_VERSION_3_3 &&
+            deviceVersion != CAMERA_DEVICE_API_VERSION_3_4 ) {
+        return hidl_string("");
+    }
+    const char* versionStr = (deviceVersion == CAMERA_DEVICE_API_VERSION_1_0) ? kHAL1_0 : kHAL3_2;
+    char deviceName[kMaxCameraDeviceNameLen];
+    snprintf(deviceName, sizeof(deviceName), "device@%s/legacy/%s",
+            versionStr, cameraId.c_str());
+    return deviceName;
+}
+
+CameraProvider::CameraProvider() :
+        camera_module_callbacks_t({sCameraDeviceStatusChange,
+                                   sTorchModeStatusChange}) {
+    mInitFailed = initialize();
+}
+
+CameraProvider::~CameraProvider() {}
+
+bool CameraProvider::initialize() {
+    camera_module_t *rawModule;
+    int err = hw_get_module(CAMERA_HARDWARE_MODULE_ID,
+            (const hw_module_t **)&rawModule);
+    if (err < 0) {
+        ALOGE("Could not load camera HAL module: %d (%s)", err, strerror(-err));
+        return true;
+    }
+
+    mModule = new CameraModule(rawModule);
+    err = mModule->init();
+    if (err != OK) {
+        ALOGE("Could not initialize camera HAL module: %d (%s)", err,
+            strerror(-err));
+        mModule.clear();
+        return true;
+    }
+    ALOGI("Loaded \"%s\" camera module", mModule->getModuleName());
+
+    mNumberOfLegacyCameras = mModule->getNumberOfCameras();
+    for (int i = 0; i < mNumberOfLegacyCameras; i++) {
+        char cameraId[kMaxCameraIdLen];
+        snprintf(cameraId, sizeof(cameraId), "%d", i);
+        std::string cameraIdStr(cameraId);
+        mCameraStatusMap[cameraIdStr] = CAMERA_DEVICE_STATUS_PRESENT;
+        mCameraIds.add(cameraIdStr);
+
+        // initialize mCameraDeviceNames and mOpenLegacySupported
+        mOpenLegacySupported[cameraIdStr] = false;
+        int deviceVersion = mModule->getDeviceVersion(i);
+        mCameraDeviceNames.add(
+                std::make_pair(cameraIdStr,
+                               getHidlDeviceName(cameraIdStr, deviceVersion)));
+        if (deviceVersion >= CAMERA_DEVICE_API_VERSION_3_2 &&
+                mModule->isOpenLegacyDefined()) {
+            // try open_legacy to see if it actually works
+            struct hw_device_t* halDev = nullptr;
+            int ret = mModule->openLegacy(cameraId, CAMERA_DEVICE_API_VERSION_1_0, &halDev);
+            if (ret == 0) {
+                mOpenLegacySupported[cameraIdStr] = true;
+                halDev->close(halDev);
+                mCameraDeviceNames.add(
+                        std::make_pair(cameraIdStr,
+                                getHidlDeviceName(cameraIdStr, CAMERA_DEVICE_API_VERSION_1_0)));
+            } else if (ret == -EBUSY || ret == -EUSERS) {
+                // Looks like this provider instance is not initialized during
+                // system startup and there are other camera users already.
+                // Not a good sign but not fatal.
+                ALOGW("%s: open_legacy try failed!", __FUNCTION__);
+            }
+        }
+    }
+
+    // Setup vendor tags here so HAL can setup vendor keys in camera characteristics
+    VendorTagDescriptor::clearGlobalVendorTagDescriptor();
+    bool setupSucceed = setUpVendorTags();
+    return !setupSucceed; // return flag here is mInitFailed
+}
+
+bool CameraProvider::setUpVendorTags() {
+    ATRACE_CALL();
+    vendor_tag_ops_t vOps = vendor_tag_ops_t();
+
+    // Check if vendor operations have been implemented
+    if (!mModule->isVendorTagDefined()) {
+        ALOGI("%s: No vendor tags defined for this device.", __FUNCTION__);
+        return false;
+    }
+
+    mModule->getVendorTagOps(&vOps);
+
+    // Ensure all vendor operations are present
+    if (vOps.get_tag_count == nullptr || vOps.get_all_tags == nullptr ||
+            vOps.get_section_name == nullptr || vOps.get_tag_name == nullptr ||
+            vOps.get_tag_type == nullptr) {
+        ALOGE("%s: Vendor tag operations not fully defined. Ignoring definitions."
+               , __FUNCTION__);
+        return false;
+    }
+
+    // Read all vendor tag definitions into a descriptor
+    sp<VendorTagDescriptor> desc;
+    status_t res;
+    if ((res = VendorTagDescriptor::createDescriptorFromOps(&vOps, /*out*/desc))
+            != OK) {
+        ALOGE("%s: Could not generate descriptor from vendor tag operations,"
+              "received error %s (%d). Camera clients will not be able to use"
+              "vendor tags", __FUNCTION__, strerror(res), res);
+        return false;
+    }
+
+    // Set the global descriptor to use with camera metadata
+    VendorTagDescriptor::setAsGlobalVendorTagDescriptor(desc);
+    const SortedVector<String8>* sectionNames = desc->getAllSectionNames();
+    size_t numSections = sectionNames->size();
+    std::vector<std::vector<VendorTag>> tagsBySection(numSections);
+    int tagCount = desc->getTagCount();
+    std::vector<uint32_t> tags(tagCount);
+    desc->getTagArray(tags.data());
+    for (int i = 0; i < tagCount; i++) {
+        VendorTag vt;
+        vt.tagId = tags[i];
+        vt.tagName = desc->getTagName(tags[i]);
+        vt.tagType = (CameraMetadataType) desc->getTagType(tags[i]);
+        ssize_t sectionIdx = desc->getSectionIndex(tags[i]);
+        tagsBySection[sectionIdx].push_back(vt);
+    }
+    mVendorTagSections.resize(numSections);
+    for (size_t s = 0; s < numSections; s++) {
+        mVendorTagSections[s].sectionName = (*sectionNames)[s].string();
+        mVendorTagSections[s].tags = tagsBySection[s];
+    }
+    return true;
+}
+
+// Methods from ::android::hardware::camera::provider::V2_4::ICameraProvider follow.
+Return<Status> CameraProvider::setCallback(const sp<ICameraProviderCallback>& callback)  {
+    {
+        Mutex::Autolock _l(mCbLock);
+        mCallbacks = callback;
+    } // release lock here because HAL might send callbacks in setCallbacks call
+    return getHidlStatus(mModule->setCallbacks(this));
+}
+
+Return<void> CameraProvider::getVendorTags(getVendorTags_cb _hidl_cb)  {
+    _hidl_cb(Status::OK, mVendorTagSections);
+    return Void();
+}
+
+Return<void> CameraProvider::getCameraIdList(getCameraIdList_cb _hidl_cb)  {
+    std::vector<hidl_string> deviceNameList;
+    for (auto const& deviceNamePair : mCameraDeviceNames) {
+        if (mCameraStatusMap[deviceNamePair.first] == CAMERA_DEVICE_STATUS_PRESENT) {
+            deviceNameList.push_back(deviceNamePair.second);
+        }
+    }
+    hidl_vec<hidl_string> hidlDeviceNameList(deviceNameList);
+    _hidl_cb(Status::OK, hidlDeviceNameList);
+    return Void();
+}
+
+Return<void> CameraProvider::isSetTorchModeSupported(isSetTorchModeSupported_cb _hidl_cb) {
+    bool support = mModule->isSetTorchModeSupported();
+    _hidl_cb (Status::OK, support);
+    return Void();
+}
+
+Return<void> CameraProvider::getCameraDeviceInterface_V1_x(
+        const hidl_string& /*cameraDeviceName*/, getCameraDeviceInterface_V1_x_cb /*_hidl_cb*/)  {
+    // TODO implement after device 1.0 is implemented
+    return Void();
+}
+
+Return<void> CameraProvider::getCameraDeviceInterface_V3_x(
+        const hidl_string& cameraDeviceName, getCameraDeviceInterface_V3_x_cb _hidl_cb)  {
+    std::smatch sm;
+    bool match = matchDeviceName(cameraDeviceName, sm);
+    if (!match) {
+        _hidl_cb(Status::ILLEGAL_ARGUMENT, nullptr);
+        return Void();
+    }
+
+    std::string cameraId = sm[2];
+    std::string deviceVersion = sm[1];
+    std::string deviceName(cameraDeviceName.c_str());
+    ssize_t index = mCameraDeviceNames.indexOf(std::make_pair(cameraId, deviceName));
+    if (index == NAME_NOT_FOUND) { // Either an illegal name or a device version mismatch
+        Status status = Status::OK;
+        ssize_t idx = mCameraIds.indexOf(cameraId);
+        if (idx == NAME_NOT_FOUND) {
+            ALOGE("%s: cannot find camera %s!", __FUNCTION__, cameraId.c_str());
+            status = Status::ILLEGAL_ARGUMENT;
+        } else { // invalid version
+            ALOGE("%s: camera device %s does not support version %s!",
+                    __FUNCTION__, cameraId.c_str(), deviceVersion.c_str());
+            status = Status::OPERATION_NOT_SUPPORTED;
+        }
+        _hidl_cb(status, nullptr);
+        return Void();
+    }
+
+    if (mCameraStatusMap.count(cameraId) == 0 ||
+            mCameraStatusMap[cameraId] != CAMERA_DEVICE_STATUS_PRESENT) {
+        _hidl_cb(Status::ILLEGAL_ARGUMENT, nullptr);
+        return Void();
+    }
+
+    // TODO: we also need to keep a wp list of all generated devices to notify
+    //       devices of device present status change, but then each device might
+    //       need a sp<provider> to keep provider alive until all device closed?
+    //       Problem: do we have external camera products to test this?
+    sp<android::hardware::camera::device::V3_2::implementation::CameraDevice> device =
+            new android::hardware::camera::device::V3_2::implementation::CameraDevice(
+                    mModule, cameraId, mCameraDeviceNames);
+
+    if (device == nullptr) {
+        ALOGE("%s: cannot allocate camera device for id %s", __FUNCTION__, cameraId.c_str());
+        _hidl_cb(Status::INTERNAL_ERROR, nullptr);
+        return Void();
+    }
+
+    if (device->isInitFailed()) {
+        ALOGE("%s: camera device %s init failed!", __FUNCTION__, cameraId.c_str());
+        device = nullptr;
+        _hidl_cb(Status::INTERNAL_ERROR, nullptr);
+        return Void();
+    }
+
+    _hidl_cb (Status::OK, device);
+    return Void();
+}
+
+ICameraProvider* HIDL_FETCH_ICameraProvider(const char* name) {
+    if (strcmp(name, kLegacyProviderName) != 0) {
+        return nullptr;
+    }
+    CameraProvider* provider = new CameraProvider();
+    if (provider == nullptr) {
+        ALOGE("%s: cannot allocate camera provider!", __FUNCTION__);
+        return nullptr;
+    }
+    if (provider->isInitFailed()) {
+        ALOGE("%s: camera provider init failed!", __FUNCTION__);
+        delete provider;
+        return nullptr;
+    }
+    return provider;
+}
+
+} // namespace implementation
+}  // namespace V2_4
+}  // namespace provider
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
diff --git a/camera/provider/2.4/default/CameraProvider.h b/camera/provider/2.4/default/CameraProvider.h
new file mode 100644
index 0000000..8497ff3
--- /dev/null
+++ b/camera/provider/2.4/default/CameraProvider.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2016 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_CAMERA_PROVIDER_V2_4_CAMERAPROVIDER_H
+#define ANDROID_HARDWARE_CAMERA_PROVIDER_V2_4_CAMERAPROVIDER_H
+
+#include "hardware/camera_common.h"
+#include "utils/Mutex.h"
+#include "utils/SortedVector.h"
+#include <android/hardware/camera/provider/2.4/ICameraProvider.h>
+#include <hidl/Status.h>
+#include <hidl/MQDescriptor.h>
+#include "CameraModule.h"
+#include "VendorTagDescriptor.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace provider {
+namespace V2_4 {
+namespace implementation {
+
+using ::android::hardware::camera::common::V1_0::CameraDeviceStatus;
+using ::android::hardware::camera::common::V1_0::Status;
+using ::android::hardware::camera::common::V1_0::TorchModeStatus;
+using ::android::hardware::camera::common::V1_0::VendorTag;
+using ::android::hardware::camera::common::V1_0::VendorTagSection;
+using ::android::hardware::camera::common::V1_0::helper::CameraModule;
+using ::android::hardware::camera::common::V1_0::helper::VendorTagDescriptor;
+using ::android::hardware::camera::provider::V2_4::ICameraProvider;
+using ::android::hardware::camera::provider::V2_4::ICameraProviderCallback;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+using ::android::Mutex;
+
+struct CameraProvider : public ICameraProvider, public camera_module_callbacks_t {
+    CameraProvider();
+    ~CameraProvider();
+
+    // Caller must use this method to check if CameraProvider ctor failed
+    bool isInitFailed() { return mInitFailed; }
+
+    // Methods from ::android::hardware::camera::provider::V2_4::ICameraProvider follow.
+    Return<Status> setCallback(const sp<ICameraProviderCallback>& callback) override;
+    Return<void> getVendorTags(getVendorTags_cb _hidl_cb) override;
+    Return<void> getCameraIdList(getCameraIdList_cb _hidl_cb) override;
+    Return<void> isSetTorchModeSupported(isSetTorchModeSupported_cb _hidl_cb) override;
+    Return<void> getCameraDeviceInterface_V1_x(
+            const hidl_string& cameraDeviceName,
+            getCameraDeviceInterface_V1_x_cb _hidl_cb) override;
+    Return<void> getCameraDeviceInterface_V3_x(
+            const hidl_string& cameraDeviceName,
+            getCameraDeviceInterface_V3_x_cb _hidl_cb) override;
+
+private:
+    Mutex mCbLock;
+    sp<ICameraProviderCallback> mCallbacks = nullptr;
+
+    sp<CameraModule> mModule;
+
+    int mNumberOfLegacyCameras;
+    std::map<std::string, camera_device_status_t> mCameraStatusMap; // camera id -> status
+    std::map<std::string, bool> mOpenLegacySupported; // camera id -> open_legacy HAL1.0 supported
+    SortedVector<std::string> mCameraIds; // the "0"/"1" legacy camera Ids
+    // (cameraId string, hidl device name) pairs
+    SortedVector<std::pair<std::string, std::string>> mCameraDeviceNames;
+
+    // Must be queried before using any APIs.
+    // APIs will only work when this returns true
+    bool mInitFailed;
+    bool initialize();
+
+    hidl_vec<VendorTagSection> mVendorTagSections;
+    bool setUpVendorTags();
+
+    // extract legacy camera ID/device version from a HIDL device name
+    static bool matchDeviceName(const hidl_string& deviceName, std::smatch& sm);
+    static std::string getLegacyCameraId(const hidl_string& deviceName);
+    static int getCameraDeviceVersion(const hidl_string& deviceName);
+
+    // create HIDL device name from camera ID and device version
+    static std::string getHidlDeviceName(std::string cameraId, int deviceVersion);
+
+    // convert conventional HAL status to HIDL Status
+    static Status getHidlStatus(int);
+
+    // static callback forwarding methods
+    static void sCameraDeviceStatusChange(
+        const struct camera_module_callbacks* callbacks,
+        int camera_id,
+        int new_status);
+    static void sTorchModeStatusChange(
+        const struct camera_module_callbacks* callbacks,
+        const char* camera_id,
+        int new_status);
+};
+
+extern "C" ICameraProvider* HIDL_FETCH_ICameraProvider(const char* name);
+
+}  // namespace implementation
+}  // namespace V2_4
+}  // namespace provider
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_CAMERA_PROVIDER_V2_4_CAMERAPROVIDER_H
diff --git a/camera/provider/2.4/vts/functional/Android.bp b/camera/provider/2.4/vts/functional/Android.bp
new file mode 100644
index 0000000..4947c17
--- /dev/null
+++ b/camera/provider/2.4/vts/functional/Android.bp
@@ -0,0 +1,36 @@
+//
+// Copyright (C) 2016 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: "camera_hidl_hal_test",
+    gtest: true,
+    srcs: ["camera_hidl_hal_test.cpp"],
+    shared_libs: [
+        "liblog",
+        "libhidlbase",
+        "libhidltransport",
+        "libcutils",
+        "libutils",
+        "android.hardware.camera.provider@2.4",
+        "android.hardware.camera.device@3.2",
+        "libcamera_metadata"
+    ],
+    static_libs: ["libgtest"],
+    cflags: [
+        "-O0",
+        "-g",
+    ],
+}
diff --git a/camera/provider/2.4/vts/functional/camera_hidl_hal_test.cpp b/camera/provider/2.4/vts/functional/camera_hidl_hal_test.cpp
new file mode 100644
index 0000000..0eb291c
--- /dev/null
+++ b/camera/provider/2.4/vts/functional/camera_hidl_hal_test.cpp
@@ -0,0 +1,515 @@
+/*
+ * Copyright (C) 2016 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 "camera_hidl_hal_test"
+#include <android/hardware/camera/provider/2.4/ICameraProvider.h>
+#include <android/hardware/camera/device/3.2/ICameraDevice.h>
+#include <android/log.h>
+#include <gtest/gtest.h>
+#include <regex>
+#include "system/camera_metadata.h"
+
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_handle;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::sp;
+using ::android::hardware::camera::common::V1_0::Status;
+using ::android::hardware::camera::common::V1_0::CameraDeviceStatus;
+using ::android::hardware::camera::common::V1_0::TorchMode;
+using ::android::hardware::camera::common::V1_0::TorchModeStatus;
+using ::android::hardware::camera::provider::V2_4::ICameraProvider;
+using ::android::hardware::camera::provider::V2_4::ICameraProviderCallback;
+using ::android::hardware::camera::device::V3_2::CaptureRequest;
+using ::android::hardware::camera::device::V3_2::CaptureResult;
+using ::android::hardware::camera::device::V3_2::ICameraDeviceCallback;
+using ::android::hardware::camera::device::V3_2::ICameraDeviceSession;
+using ::android::hardware::camera::device::V3_2::NotifyMsg;
+using ::android::hardware::camera::device::V3_2::RequestTemplate;
+
+#define CAMERA_PASSTHROUGH_SERVICE_NAME "legacy/0"
+
+namespace {
+    // "device@<version>/legacy/<id>"
+    const char *kDeviceNameRE = "device@([0-9]+\\.[0-9]+)/legacy/(.+)";
+    const int CAMERA_DEVICE_API_VERSION_3_2 = 0x302;
+    const int CAMERA_DEVICE_API_VERSION_1_0 = 0x100;
+    const char *kHAL3_2 = "3.2";
+    const char *kHAL1_0 = "1.0";
+
+    bool matchDeviceName(const hidl_string& deviceName, std::smatch& sm) {
+        std::regex e(kDeviceNameRE);
+        std::string deviceNameStd(deviceName.c_str());
+        return std::regex_match(deviceNameStd, sm, e);
+    }
+
+    int getCameraDeviceVersion(const hidl_string& deviceName) {
+        std::smatch sm;
+        bool match = matchDeviceName(deviceName, sm);
+        if (!match) {
+            return -1;
+        }
+        if (sm[1].compare(kHAL3_2) == 0) {
+            // maybe switched to 3.4 or define the hidl version enumlater
+            return CAMERA_DEVICE_API_VERSION_3_2;
+        } else if (sm[1].compare(kHAL1_0) == 0) {
+            return CAMERA_DEVICE_API_VERSION_1_0;
+        }
+        return 0;
+    }
+}
+
+// Test environment for camera
+class CameraHidlEnvironment : public ::testing::Environment {
+public:
+    // get the test environment singleton
+    static CameraHidlEnvironment* Instance() {
+        static CameraHidlEnvironment* instance = new CameraHidlEnvironment;
+        return instance;
+    }
+
+    virtual void SetUp() override;
+    virtual void TearDown() override;
+
+    sp<ICameraProvider> mProvider;
+
+private:
+    CameraHidlEnvironment() {}
+
+    GTEST_DISALLOW_COPY_AND_ASSIGN_(CameraHidlEnvironment);
+};
+
+void CameraHidlEnvironment::SetUp() {
+    // TODO: test the binderized mode
+    mProvider = ICameraProvider::getService(CAMERA_PASSTHROUGH_SERVICE_NAME, true);
+    // TODO: handle the device doesn't have any camera case
+    ALOGI_IF(mProvider, "provider is not nullptr, %p", mProvider.get());
+    ASSERT_NE(mProvider, nullptr);
+}
+
+void CameraHidlEnvironment::TearDown() {
+    ALOGI("TearDown CameraHidlEnvironment");
+}
+
+// The main test class for camera HIDL HAL.
+class CameraHidlTest : public ::testing::Test {
+public:
+    virtual void SetUp() override {}
+    virtual void TearDown() override {}
+
+    hidl_vec<hidl_string> getCameraDeviceNames();
+
+    struct EmptyDeviceCb : public ICameraDeviceCallback {
+        virtual Return<void> processCaptureResult(const CaptureResult& /*result*/) override {
+            ALOGI("processCaptureResult callback");
+            ADD_FAILURE(); // Empty callback should not reach here
+            return Void();
+        }
+
+        virtual Return<void> notify(const NotifyMsg& /*msg*/) override {
+            ALOGI("notify callback");
+            ADD_FAILURE(); // Empty callback should not reach here
+            return Void();
+        }
+    };
+};
+
+hidl_vec<hidl_string> CameraHidlTest::getCameraDeviceNames() {
+    CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+    hidl_vec<hidl_string> cameraDeviceNames;
+    env->mProvider->getCameraIdList(
+        [&](auto status, const auto& idList) {
+            ALOGI("getCameraIdList returns status:%d", (int)status);
+            for (size_t i = 0; i < idList.size(); i++) {
+                ALOGI("Camera Id[%zu] is %s", i, idList[i].c_str());
+            }
+            ASSERT_EQ(Status::OK, status);
+            cameraDeviceNames = idList;
+        });
+    return cameraDeviceNames;
+}
+
+// Test if ICameraProvider::isTorchModeSupported returns Status::OK
+TEST_F(CameraHidlTest, isTorchModeSupported) {
+    CameraHidlEnvironment::Instance()->mProvider->isSetTorchModeSupported(
+        [&](auto status, bool support) {
+            ALOGI("isSetTorchModeSupported returns status:%d supported:%d",
+                    (int)status, support);
+            ASSERT_EQ(Status::OK, status);
+        });
+}
+
+// TODO: consider removing this test if getCameraDeviceNames() has the same coverage
+TEST_F(CameraHidlTest, getCameraIdList) {
+    CameraHidlEnvironment::Instance()->mProvider->getCameraIdList(
+        [&](auto status, const auto& idList) {
+            ALOGI("getCameraIdList returns status:%d", (int)status);
+            for (size_t i = 0; i < idList.size(); i++) {
+                ALOGI("Camera Id[%zu] is %s", i, idList[i].c_str());
+            }
+            ASSERT_EQ(Status::OK, status);
+            // This is true for internal camera provider.
+            // Not necessary hold for external cameras providers
+            ASSERT_GT(idList.size(), 0u);
+        });
+}
+
+// Test if ICameraProvider::getVendorTags returns Status::OK
+TEST_F(CameraHidlTest, getVendorTags) {
+    CameraHidlEnvironment::Instance()->mProvider->getVendorTags(
+        [&](auto status, const auto& vendorTagSecs) {
+            ALOGI("getVendorTags returns status:%d numSections %zu",
+                    (int)status, vendorTagSecs.size());
+            for (size_t i = 0; i < vendorTagSecs.size(); i++) {
+                ALOGI("Vendor tag section %zu name %s",
+                        i, vendorTagSecs[i].sectionName.c_str());
+                for (size_t j = 0; j < vendorTagSecs[i].tags.size(); j++) {
+                    const auto& tag = vendorTagSecs[i].tags[j];
+                    ALOGI("Vendor tag id %u name %s type %d",
+                            tag.tagId,
+                            tag.tagName.c_str(),
+                            (int) tag.tagType);
+                }
+            }
+            ASSERT_EQ(Status::OK, status);
+        });
+}
+
+// Test if ICameraProvider::setCallback returns Status::OK
+TEST_F(CameraHidlTest, setCallback) {
+    CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+    struct ProviderCb : public ICameraProviderCallback {
+        virtual Return<void> cameraDeviceStatusChange(
+                const hidl_string& cameraDeviceName,
+                CameraDeviceStatus newStatus) override {
+            ALOGI("camera device status callback name %s, status %d",
+                    cameraDeviceName.c_str(), (int) newStatus);
+            return Void();
+        }
+
+        virtual Return<void> torchModeStatusChange(
+                const hidl_string& cameraDeviceName,
+                TorchModeStatus newStatus) override {
+            ALOGI("Torch mode status callback name %s, status %d",
+                    cameraDeviceName.c_str(), (int) newStatus);
+            return Void();
+        }
+    };
+    sp<ProviderCb> cb = new ProviderCb;
+    auto status = env->mProvider->setCallback(cb);
+    ASSERT_EQ(Status::OK, status);
+    // TODO: right now no callbacks are fired because there is no external camera
+    //       or torch mode change. Need to test torch API in CameraDevice test later.
+}
+
+// Test if ICameraProvider::getCameraDeviceInterface_V3_x returns Status::OK and non-null device
+TEST_F(CameraHidlTest, getCameraDeviceInterface_V3_x) {
+    CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+
+    for (const auto& name : cameraDeviceNames) {
+        if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
+            env->mProvider->getCameraDeviceInterface_V3_x(
+                name,
+                [&](auto status, const auto& device3_2) {
+                    ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
+                    ASSERT_EQ(Status::OK, status);
+                    ASSERT_NE(device3_2, nullptr);
+                });
+        }
+    }
+}
+
+TEST_F(CameraHidlTest, getResourceCost) {
+    CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+
+    for (const auto& name : cameraDeviceNames) {
+        if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
+            ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2;
+            ALOGI("getResourceCost: Testing camera device %s", name.c_str());
+            env->mProvider->getCameraDeviceInterface_V3_x(
+                name,
+                [&](auto status, const auto& device) {
+                    ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
+                    ASSERT_EQ(Status::OK, status);
+                    ASSERT_NE(device, nullptr);
+                    device3_2 = device;
+                });
+
+            device3_2->getResourceCost(
+                [&](auto status, const auto& resourceCost) {
+                    ALOGI("getResourceCost returns status:%d", (int)status);
+                    ASSERT_EQ(Status::OK, status);
+                    ALOGI("    Resource cost is %d", resourceCost.resourceCost);
+                    ASSERT_LE(resourceCost.resourceCost, 100u);
+                    for (const auto& name : resourceCost.conflictingDevices) {
+                        ALOGI("    Conflicting device: %s", name.c_str());
+                    }
+                });
+        }
+    }
+}
+
+TEST_F(CameraHidlTest, getCameraCharacteristics) {
+    CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+
+    for (const auto& name : cameraDeviceNames) {
+        if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
+            ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2;
+            ALOGI("getCameraCharacteristics: Testing camera device %s", name.c_str());
+            env->mProvider->getCameraDeviceInterface_V3_x(
+                name,
+                [&](auto status, const auto& device) {
+                    ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
+                    ASSERT_EQ(Status::OK, status);
+                    ASSERT_NE(device, nullptr);
+                    device3_2 = device;
+                });
+
+            device3_2->getCameraCharacteristics(
+                [&](auto status, const auto& chars) {
+                    ALOGI("getCameraCharacteristics returns status:%d", (int)status);
+                    ASSERT_EQ(Status::OK, status);
+                    const camera_metadata_t* metadata = (camera_metadata_t*) chars.data();
+                    size_t expectedSize = chars.size();
+                    ASSERT_EQ(0, validate_camera_metadata_structure(metadata, &expectedSize));
+                    size_t entryCount = get_camera_metadata_entry_count(metadata);
+                    // TODO: we can do better than 0 here. Need to check how many required
+                    // characteristics keys we've defined.
+                    ASSERT_GT(entryCount, 0u);
+                    ALOGI("getCameraCharacteristics metadata entry count is %zu", entryCount);
+                });
+        }
+    }
+}
+
+TEST_F(CameraHidlTest, setTorchMode) {
+    CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+    bool torchControlSupported = false;
+
+    CameraHidlEnvironment::Instance()->mProvider->isSetTorchModeSupported(
+        [&](auto status, bool support) {
+            ALOGI("isSetTorchModeSupported returns status:%d supported:%d",
+                    (int)status, support);
+            ASSERT_EQ(Status::OK, status);
+            torchControlSupported = support;
+        });
+
+    for (const auto& name : cameraDeviceNames) {
+        if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
+            ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2;
+            ALOGI("setTorchMode: Testing camera device %s", name.c_str());
+            env->mProvider->getCameraDeviceInterface_V3_x(
+                name,
+                [&](auto status, const auto& device) {
+                    ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
+                    ASSERT_EQ(Status::OK, status);
+                    ASSERT_NE(device, nullptr);
+                    device3_2 = device;
+                });
+
+            Status status = device3_2->setTorchMode(TorchMode::ON);
+            ALOGI("setTorchMode return status %d", (int)status);
+            if (!torchControlSupported) {
+                ASSERT_EQ(Status::METHOD_NOT_SUPPORTED, status);
+            } else {
+                ASSERT_TRUE(status == Status::OK || status == Status::OPERATION_NOT_SUPPORTED);
+                if (status == Status::OK) {
+                    status = device3_2->setTorchMode(TorchMode::OFF);
+                    ASSERT_EQ(Status::OK, status);
+                }
+            }
+        }
+    }
+}
+
+TEST_F(CameraHidlTest, dumpState) {
+    CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+
+    for (const auto& name : cameraDeviceNames) {
+        if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
+            ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2;
+            ALOGI("dumpState: Testing camera device %s", name.c_str());
+            env->mProvider->getCameraDeviceInterface_V3_x(
+                name,
+                [&](auto status, const auto& device) {
+                    ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
+                    ASSERT_EQ(Status::OK, status);
+                    ASSERT_NE(device, nullptr);
+                    device3_2 = device;
+                });
+
+            native_handle_t* raw_handle = native_handle_create(1, 0);
+            raw_handle->data[0] = 1; // std out
+            hidl_handle handle = raw_handle;
+            device3_2->dumpState(handle);
+            native_handle_delete(raw_handle);
+        }
+    }
+}
+
+// Open, dumpStates, then close
+TEST_F(CameraHidlTest, openClose) {
+    CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+
+    for (const auto& name : cameraDeviceNames) {
+        if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
+            ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2;
+            ALOGI("openClose: Testing camera device %s", name.c_str());
+            env->mProvider->getCameraDeviceInterface_V3_x(
+                name,
+                [&](auto status, const auto& device) {
+                    ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
+                    ASSERT_EQ(Status::OK, status);
+                    ASSERT_NE(device, nullptr);
+                    device3_2 = device;
+                });
+
+            sp<EmptyDeviceCb> cb = new EmptyDeviceCb;
+            sp<ICameraDeviceSession> session;
+            device3_2->open(
+                cb,
+                [&](auto status, const auto& newSession) {
+                    ALOGI("device::open returns status:%d", (int)status);
+                    ASSERT_EQ(Status::OK, status);
+                    ASSERT_NE(newSession, nullptr);
+                    session = newSession;
+                });
+
+            native_handle_t* raw_handle = native_handle_create(1, 0);
+            raw_handle->data[0] = 1; // std out
+            hidl_handle handle = raw_handle;
+            device3_2->dumpState(handle);
+            native_handle_delete(raw_handle);
+
+            session->close();
+            // TODO: test all session API calls return INTERNAL_ERROR after close
+            // TODO: keep a wp copy here and verify session cannot be promoted out of this scope
+        }
+    }
+}
+
+TEST_F(CameraHidlTest, constructDefaultRequestSettings) {
+    CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+
+    for (const auto& name : cameraDeviceNames) {
+        if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
+            ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2;
+            ALOGI("constructDefaultRequestSettings: Testing camera device %s", name.c_str());
+            env->mProvider->getCameraDeviceInterface_V3_x(
+                name,
+                [&](auto status, const auto& device) {
+                    ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
+                    ASSERT_EQ(Status::OK, status);
+                    ASSERT_NE(device, nullptr);
+                    device3_2 = device;
+                });
+
+            sp<EmptyDeviceCb> cb = new EmptyDeviceCb;
+            sp<ICameraDeviceSession> session;
+            device3_2->open(
+                cb,
+                [&](auto status, const auto& newSession) {
+                    ALOGI("device::open returns status:%d", (int)status);
+                    ASSERT_EQ(Status::OK, status);
+                    ASSERT_NE(newSession, nullptr);
+                    session = newSession;
+                });
+
+            for (uint32_t t = (uint32_t) RequestTemplate::PREVIEW;
+                    t <= (uint32_t) RequestTemplate::MANUAL; t++) {
+                RequestTemplate reqTemplate = (RequestTemplate) t;
+                session->constructDefaultRequestSettings(
+                    reqTemplate,
+                    [&](auto status, const auto& req) {
+                        ALOGI("constructDefaultRequestSettings returns status:%d", (int)status);
+                        if (reqTemplate == RequestTemplate::ZERO_SHUTTER_LAG ||
+                                reqTemplate == RequestTemplate::MANUAL) {
+                            // optional templates
+                            ASSERT_TRUE(status == Status::OK || status == Status::ILLEGAL_ARGUMENT);
+                        } else {
+                            ASSERT_EQ(Status::OK, status);
+                        }
+
+                        if (status == Status::OK) {
+                            const camera_metadata_t* metadata =
+                                (camera_metadata_t*) req.data();
+                            size_t expectedSize = req.size();
+                            ASSERT_EQ(0, validate_camera_metadata_structure(
+                                    metadata, &expectedSize));
+                            size_t entryCount = get_camera_metadata_entry_count(metadata);
+                            // TODO: we can do better than 0 here. Need to check how many required
+                            // request keys we've defined for each template
+                            ASSERT_GT(entryCount, 0u);
+                            ALOGI("template %u metadata entry count is %zu", t, entryCount);
+                        } else {
+                            ASSERT_EQ(0u, req.size());
+                        }
+                    });
+            }
+            session->close();
+        }
+    }
+}
+
+TEST_F(CameraHidlTest, configureStreams) {
+    CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+
+    for (const auto& name : cameraDeviceNames) {
+        if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
+            ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2;
+            ALOGI("configureStreams: Testing camera device %s", name.c_str());
+            env->mProvider->getCameraDeviceInterface_V3_x(
+                name,
+                [&](auto status, const auto& device) {
+                    ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
+                    ASSERT_EQ(Status::OK, status);
+                    ASSERT_NE(device, nullptr);
+                    device3_2 = device;
+                });
+
+            sp<EmptyDeviceCb> cb = new EmptyDeviceCb;
+            sp<ICameraDeviceSession> session;
+            device3_2->open(
+                cb,
+                [&](auto status, const auto& newSession) {
+                    ALOGI("device::open returns status:%d", (int)status);
+                    ASSERT_EQ(Status::OK, status);
+                    ASSERT_NE(newSession, nullptr);
+                    session = newSession;
+                });
+
+
+            session->close();
+        }
+    }
+}
+
+int main(int argc, char **argv) {
+  ::testing::AddGlobalTestEnvironment(CameraHidlEnvironment::Instance());
+  ::testing::InitGoogleTest(&argc, argv);
+  int status = RUN_ALL_TESTS();
+  ALOGI("Test result = %d", status);
+  return status;
+}
diff --git a/drm/crypto/1.0/ICryptoFactory.hal b/drm/crypto/1.0/ICryptoFactory.hal
index 0ac7828..4b60ccc 100644
--- a/drm/crypto/1.0/ICryptoFactory.hal
+++ b/drm/crypto/1.0/ICryptoFactory.hal
@@ -40,8 +40,9 @@
      * @param uuid uniquely identifies the drm scheme. See
      * http://dashif.org/identifiers/protection for uuid assignments
      * @param initData scheme-specific init data.
-     * @return status the status of the call. If the plugin can't
-     * be created, the HAL implementation must return ERROR_DRM_CANNOT_HANDLE.
+     * @return status the status of the call. The HAL implementation must return
+     * OK if the plugin is created and ERROR_DRM_CANNOT_HANDLE if the plugin
+     * cannot be created.
      * @return cryptoPlugin the created ICryptoPlugin
      */
     createPlugin(uint8_t[16] uuid, vec<uint8_t> initData)
diff --git a/drm/crypto/1.0/ICryptoPlugin.hal b/drm/crypto/1.0/ICryptoPlugin.hal
index e86c9f2..e892e3c 100644
--- a/drm/crypto/1.0/ICryptoPlugin.hal
+++ b/drm/crypto/1.0/ICryptoPlugin.hal
@@ -74,8 +74,8 @@
      * call to operate on a range of subsamples in a single call
      * @param source the input buffer for the decryption
      * @param destination the output buffer for the decryption
-     * @return status the status of the call. The status must be one of
-     * the following: ERROR_DRM_NO_LICENSE if no license keys have been
+     * @return status the status of the call. The status must be OK or one of
+     * the following errors: ERROR_DRM_NO_LICENSE if no license keys have been
      * loaded, ERROR_DRM_LICENSE_EXPIRED if the license keys have expired,
      * ERROR_DRM_RESOURCE_BUSY if the resources required to perform the
      * decryption are not available, ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION
@@ -83,12 +83,9 @@
      * ERROR_DRM_SESSION_NOT_OPENED if the decrypt session is not opened, or
      * ERROR_DRM_CANNOT_HANDLE in other failure cases.
      * @return bytesWritten the number of bytes output from the decryption
-     * @return detailedError if the error is a vendor-specific error, the
-     * vendor's crypto HAL may provide a detailed error string to help
-     * describe the error.
      */
     decrypt(bool secure, uint8_t[16] keyId, uint8_t[16] iv, Mode mode,
         Pattern pattern, vec<SubSample> subSamples,
             memory source, DestinationBuffer destination)
-        generates(Status status, uint32_t bytesWritten, string detailedError);
+        generates(Status status, uint32_t bytesWritten);
 };
diff --git a/drm/crypto/1.0/default/CryptoFactory.cpp b/drm/crypto/1.0/default/CryptoFactory.cpp
index e67a990..187d564 100644
--- a/drm/crypto/1.0/default/CryptoFactory.cpp
+++ b/drm/crypto/1.0/default/CryptoFactory.cpp
@@ -27,7 +27,7 @@
 namespace implementation {
 
     CryptoFactory::CryptoFactory() :
-        loader("/vendor/lib/mediadrm", "createCryptoFactory", "crypto") {}
+        loader("/vendor/lib/mediadrm", "createCryptoFactory") {}
 
     // Methods from ::android::hardware::drm::crypto::V1_0::ICryptoFactory follow.
     Return<bool> CryptoFactory::isCryptoSchemeSupported(
diff --git a/drm/crypto/1.0/default/CryptoPlugin.cpp b/drm/crypto/1.0/default/CryptoPlugin.cpp
index 9173d5b..7921852 100644
--- a/drm/crypto/1.0/default/CryptoPlugin.cpp
+++ b/drm/crypto/1.0/default/CryptoPlugin.cpp
@@ -119,7 +119,7 @@
             bytesWritten = 0;
         }
 
-        _hidl_cb(toStatus(status), bytesWritten, detailMessage.c_str());
+        _hidl_cb(toStatus(status), bytesWritten);
         return Void();
     }
 
diff --git a/drm/crypto/1.0/default/TypeConvert.cpp b/drm/crypto/1.0/default/TypeConvert.cpp
index d9cca6b..ed95d15 100644
--- a/drm/crypto/1.0/default/TypeConvert.cpp
+++ b/drm/crypto/1.0/default/TypeConvert.cpp
@@ -26,6 +26,9 @@
 Status toStatus(status_t legacyStatus) {
     Status status;
     switch(legacyStatus) {
+    case android::OK:
+        status = Status::OK;
+        break;
     case android::ERROR_DRM_NO_LICENSE:
         status = Status::ERROR_DRM_NO_LICENSE;
         break;
diff --git a/drm/crypto/1.0/types.hal b/drm/crypto/1.0/types.hal
index 7e853b8..e71d73a 100644
--- a/drm/crypto/1.0/types.hal
+++ b/drm/crypto/1.0/types.hal
@@ -18,6 +18,12 @@
 
 enum Status : uint32_t {
     /**
+     * The Crypto plugin must return OK when an operation completes without any
+     * errors.
+     */
+    OK,
+
+    /**
      * The Crypto Plugin must return ERROR_DRM_NO_LICENSE if decryption is
      * attempted when the license keys have not been loaded into the crypto
      * session.
diff --git a/drm/drm/1.0/IDrmFactory.hal b/drm/drm/1.0/IDrmFactory.hal
index a58bcaa..1ef1d27 100644
--- a/drm/drm/1.0/IDrmFactory.hal
+++ b/drm/drm/1.0/IDrmFactory.hal
@@ -36,14 +36,23 @@
     isCryptoSchemeSupported(uint8_t[16] uuid) generates(bool isSupported);
 
     /**
+     * Determine if the HAL factory is able to construct plugins that support a
+     * given media container format specified by mimeType
+     *
+     * @param mimeType identifies the mime type in question
+     * @return isSupported must be true only if the scheme is supported
+     */
+    isContentTypeSupported(string mimeType) generates(bool isSupported);
+
+    /**
      * Create a drm plugin instance for the specified uuid and scheme-specific
      * initialization data.
      *
      * @param uuid uniquely identifies the drm scheme. See
      * http://dashif.org/identifiers/protection for uuid assignments
-     * @return status the status of the call. If the plugin can't be created,
-     * the HAL implementation must return ERROR_DRM_CANNOT_HANDLE.
-     * @return drmPlugin the created IDrmPlugin
+     * @return status the status of the call. The HAL implementation must return
+     * OK if the plugin is created and ERROR_DRM_CANNOT_HANDLE if the plugin
+     * cannot be created.
      */
     createPlugin(uint8_t[16] uuid) generates (Status status,
             IDrmPlugin drmPlugin);
diff --git a/drm/drm/1.0/IDrmPlugin.hal b/drm/drm/1.0/IDrmPlugin.hal
index e847805..881bf80 100644
--- a/drm/drm/1.0/IDrmPlugin.hal
+++ b/drm/drm/1.0/IDrmPlugin.hal
@@ -30,13 +30,13 @@
     /**
      * Open a new session with the DrmPlugin object. A session ID is returned
      * in the sessionId parameter.
-     * @return status the status of the call. The status must be one of
-     * ERROR_DRM_NOT_PROVISIONED if the device requires provisioning before
-     * it can open a session, ERROR_DRM_RESOURCE_BUSY if there are insufficent
-     * resources available to open a session, ERROR_DRM_CANNOT_HANDLE,
-     * if openSession is not supported at the time of the call or
-     * ERROR_DRM_INVALID_STATE if the HAL is in a state where a session cannot
-     * be opened.
+     * @return status the status of the call. The status must be OK or one of
+     * the following errors: ERROR_DRM_NOT_PROVISIONED if the device requires
+     * provisioning before it can open a session, ERROR_DRM_RESOURCE_BUSY if
+     * there are insufficent resources available to open a session,
+     * ERROR_DRM_CANNOT_HANDLE, if openSession is not supported at the time of
+     * the call or ERROR_DRM_INVALID_STATE if the HAL is in a state where a
+     * session cannot be opened.
      * @return sessionId the session ID for the newly opened session
      */
     openSession() generates (Status status, SessionId sessionId);
@@ -45,9 +45,9 @@
      * Close a session on the DrmPlugin object
      *
      * @param sessionId the session id the call applies to
-     * @return status the status of the call.  The status must be one of
-     * ERROR_DRM_SESSION_NOT_OPENED if the session is not opened,
-     * BAD_VALUE if the sessionId is invalid or ERROR_DRM_INVALID_STATE
+     * @return status the status of the call.  The status must be OK or one of
+     * the following errors: ERROR_DRM_SESSION_NOT_OPENED if the session is not
+     * opened, BAD_VALUE if the sessionId is invalid or ERROR_DRM_INVALID_STATE
      * if the HAL is in a state where the session cannot be closed.
      */
     closeSession(SessionId sessionId) generates (Status status);
@@ -75,13 +75,13 @@
      * allow a client application to provide additional message parameters to
      * the server.
      *
-     * @return status the status of the call.  The status must be one of
-     * ERROR_DRM_SESSION_NOT_OPENED if the session is not opened,
-     * ERROR_DRM_NOT_PROVISIONED if the device requires provisioning before
-     * it can generate a key request, ERROR_DRM_CANNOT_HANDLE if keyKeyRequest
-     * is not supported at the time of the call, BAD_VALUE if any parameters
-     * are invalid or ERROR_DRM_INVALID_STATE if the HAL is in a state where
-     * a key request cannot be generated.
+     * @return status the status of the call.  The status must be OK or one of
+     * the following errors: ERROR_DRM_SESSION_NOT_OPENED if the session is not
+     * opened, ERROR_DRM_NOT_PROVISIONED if the device requires provisioning
+     * before it can generate a key request, ERROR_DRM_CANNOT_HANDLE if
+     * getKeyRequest is not supported at the time of the call, BAD_VALUE if any
+     * parameters are invalid or ERROR_DRM_INVALID_STATE if the HAL is in a state
+     * where a key request cannot be generated.
      * @return request if successful, the opaque key request blob is returned
      * @return requestType indicates type information about the returned
      * request. The type may be one of INITIAL, RENEWAL or RELEASE. An
@@ -109,12 +109,12 @@
      * @param response the response from the key server that is being
      * provided to the drm HAL.
      *
-     * @return status the status of the call.  The status must be one of
-     * ERROR_DRM_SESSION_NOT_OPENED if the session is not opened,
-     * ERROR_DRM_NOT_PROVISIONED if the device requires provisioning before
-     * it can handle the key response, ERROR_DRM_DEVICE_REVOKED if the device
-     * has been disabled by the license policy, ERROR_DRM_CANNOT_HANDLE if
-     * provideKeyResponse is not supported at the time of the call, BAD_VALUE
+     * @return status the status of the call.  The status must be OK or one of
+     * the following errors: ERROR_DRM_SESSION_NOT_OPENED if the session is not
+     * opened, ERROR_DRM_NOT_PROVISIONED if the device requires provisioning
+     * before it can handle the key response, ERROR_DRM_DEVICE_REVOKED if the
+     * device has been disabled by the license policy, ERROR_DRM_CANNOT_HANDLE
+     * if provideKeyResponse is not supported at the time of the call, BAD_VALUE
      * if any parameters are invalid or ERROR_DRM_INVALID_STATE if the HAL is
      * in a state where a key response cannot be handled.
      * @return keySetId when the response is for an offline key request, a
@@ -130,9 +130,9 @@
      * Remove the current keys from a session
      *
      * @param sessionId the session id the call applies to
-     * @return status the status of the call.  The status must be one of
-     * ERROR_DRM_SESSION_NOT_OPENED if the session is not opened,
-     * BAD_VALUE if the sessionId is invalid or ERROR_DRM_INVALID_STATE
+     * @return status the status of the call.  The status must be OK or one of
+     * the following errors: ERROR_DRM_SESSION_NOT_OPENED if the session is not
+     * opened, BAD_VALUE if the sessionId is invalid or ERROR_DRM_INVALID_STATE
      * if the HAL is in a state where the keys cannot be removed.
      */
     removeKeys(SessionId sessionId) generates (Status status);
@@ -143,9 +143,9 @@
      * @param sessionId the session id the call applies to
      * @param keySetId identifies the keys to load, obtained from a prior
      * call to provideKeyResponse().
-     * @return status the status of the call. The status must be one of
-     * ERROR_DRM_SESSION_NOT_OPENED if the session is not opened,
-     * BAD_VALUE if any parameters are invalid or ERROR_DRM_INVALID_STATE
+     * @return status the status of the call. The status must be OK or one of
+     * the following errors: ERROR_DRM_SESSION_NOT_OPENED if the session is not
+     * opened, BAD_VALUE if any parameters are invalid or ERROR_DRM_INVALID_STATE
      * if the HAL is in a state where keys cannot be restored.
      */
     restoreKeys(SessionId sessionId,
@@ -159,9 +159,9 @@
      * the field names for a particular drm scheme.
      *
      * @param sessionId the session id the call applies to
-     * @return status the status of the call. The status must be one of
-     * ERROR_DRM_SESSION_NOT_OPENED if the session is not opened,
-     * BAD_VALUE if the sessionId is invalid or ERROR_DRM_INVALID_STATE
+     * @return status the status of the call. The status must be OK or one of
+     * the following errors: ERROR_DRM_SESSION_NOT_OPENED if the session is not
+     * opened, BAD_VALUE if the sessionId is invalid or ERROR_DRM_INVALID_STATE
      * if the HAL is in a state where key status cannot be queried.
      * @return infoList a list of name value pairs describing the license
      */
@@ -178,10 +178,10 @@
      * @param certificateAuthority identifies the certificate authority. A
      * certificate authority (CA) is an entity which issues digital certificates
      * for use by other parties. It is an example of a trusted third party.
-     * @return status the status of the call. The status must be one of
-     * BAD_VALUE if the sessionId is invalid or ERROR_DRM_INVALID_STATE
-     * if the HAL is in a state where the provision request cannot be
-     * generated.
+     * @return status the status of the call. The status must be OK or one of
+     * the following errors: BAD_VALUE if the sessionId is invalid or
+     * ERROR_DRM_INVALID_STATE if the HAL is in a state where the provision
+     * request cannot be generated.
      * @return request if successful the opaque certificate request blob
      * is returned
      * @return defaultUrl URL that the provisioning request should be
@@ -200,11 +200,11 @@
      * @param response the opaque provisioning response received by the
      * app from a provisioning server.
 
-     * @return status the status of the call. The status must be one of
-     * ERROR_DRM_DEVICE_REVOKED if the device has been disabled by the license
-     * policy, BAD_VALUE if any parameters are invalid or ERROR_DRM_INVALID_STATE
-     * if the HAL is in a state where the provision response cannot be
-     * handled.
+     * @return status the status of the call. The status must be OK or one of
+     * the following errors: ERROR_DRM_DEVICE_REVOKED if the device has been
+     * disabled by the license policy, BAD_VALUE if any parameters are invalid
+     * or ERROR_DRM_INVALID_STATE if the HAL is in a state where the provision
+     * response cannot be handled.
      * @return certificate the public certificate resulting from the provisioning
      * operation, if any. An empty vector indicates that no certificate was
      * returned.
@@ -237,7 +237,7 @@
     /**
      * Get all secure stops on the device
      *
-     * @return status the status of the call. The status must be
+     * @return status the status of the call. The status must be OK or
      * ERROR_DRM_INVALID_STATE if the HAL is in a state where the secure stops
      * cannot be returned.
      * @return secureStops a list of the secure stop opaque objects
@@ -252,9 +252,10 @@
      * secure stop ID is delivered by the key server as part of the key
      * response and must also be known by the app.
      *
-     * @return status the status of the call. The status must be one of
-     * BAD_VALUE if the secureStopId is invalid or ERROR_DRM_INVALID_STATE
-     * if the HAL is in a state where the secure stop cannot be returned.
+     * @return status the status of the call. The status must be OK or one of
+     * the following errors: BAD_VALUE if the secureStopId is invalid or
+     * ERROR_DRM_INVALID_STATE if the HAL is in a state where the secure stop
+     * cannot be returned.
      * @return secureStop the secure stop opaque object
      */
 
@@ -264,7 +265,7 @@
     /**
      * Release all secure stops on the device
      *
-     * @return status the status of the call. The status must be one of
+     * @return status the status of the call. The status must be OK or
      * ERROR_DRM_INVALID_STATE if the HAL is in a state where the secure
      * stops cannot be released.
      */
@@ -277,9 +278,10 @@
      * secure stop ID is delivered by the key server as part of the key
      * response and must also be known by the app.
      *
-     * @return status the status of the call. The status must be one of
-     * BAD_VALUE if the secureStopId is invalid or ERROR_DRM_INVALID_STATE
-     * if the HAL is in a state where the secure stop cannot be released.
+     * @return status the status of the call. The status must be OK or one of
+     * the following errors: BAD_VALUE if the secureStopId is invalid or
+     * ERROR_DRM_INVALID_STATE if the HAL is in a state where the secure stop
+     * cannot be released.
      */
     releaseSecureStop(vec<uint8_t> secureStopId) generates (Status status);
 
@@ -305,10 +307,11 @@
      * Read a string property value given the property name.
      *
      * @param propertyName the name of the property
-     * @return status the status of the call. The status must be one of
-     * BAD_VALUE if the property name is invalid, ERROR_DRM_CANNOT_HANDLE
-     * if the property is not supported, or ERROR_DRM_INVALID_STATE if the
-     * HAL is in a state where the property cannot be obtained.
+     * @return status the status of the call. The status must be OK or one of
+     * the following errors: BAD_VALUE if the property name is invalid,
+     * ERROR_DRM_CANNOT_HANDLE if the property is not supported, or
+     * ERROR_DRM_INVALID_STATE if the HAL is in a state where the property
+     * cannot be obtained.
      * @return value the property value string
      */
     getPropertyString(string propertyName)
@@ -318,10 +321,11 @@
      * Read a byte array property value given the property name.
      *
      * @param propertyName the name of the property
-     * @return status the status of the call. The status must be one of
-     * BAD_VALUE if the property name is invalid, ERROR_DRM_CANNOT_HANDLE
-     * if the property is not supported, or ERROR_DRM_INVALID_STATE if the
-     * HAL is in a state where the property cannot be obtained.
+     * @return status the status of the call. The status must be OK or one of
+     * the following errors: BAD_VALUE if the property name is invalid,
+     * ERROR_DRM_CANNOT_HANDLE if the property is not supported, or
+     * ERROR_DRM_INVALID_STATE if the HAL is in a state where the property
+     * cannot be obtained.
      * @return value the property value byte array
      */
     getPropertyByteArray(string propertyName)
@@ -332,10 +336,11 @@
      *
      * @param propertyName the name of the property
      * @param value the value to write
-     * @return status the status of the call. The status must be one of
-     * BAD_VALUE if the property name is invalid, ERROR_DRM_CANNOT_HANDLE
-     * if the property is not supported, or ERROR_DRM_INVALID_STATE if the
-     * HAL is in a state where the property cannot be set.
+     * @return status the status of the call. The status must be OK or one of
+     * the following errors: BAD_VALUE if the property name is invalid,
+     * ERROR_DRM_CANNOT_HANDLE if the property is not supported, or
+     * ERROR_DRM_INVALID_STATE if the HAL is in a state where the property
+     * cannot be set.
      */
     setPropertyString(string propertyName, string value)
         generates (Status status);
@@ -345,10 +350,11 @@
      *
      * @param propertyName the name of the property
      * @param value the value to write
-     * @return status the status of the call. The status must be one of
-     * BAD_VALUE if the property name is invalid, ERROR_DRM_CANNOT_HANDLE
-     * if the property is not supported, or ERROR_DRM_INVALID_STATE if the
-     * HAL is in a state where the property cannot be set.
+     * @return status the status of the call. The status must be OK or one of
+     * the following errors: BAD_VALUE if the property name is invalid,
+     * ERROR_DRM_CANNOT_HANDLE if the property is not supported, or
+     * ERROR_DRM_INVALID_STATE if the HAL is in a state where the property
+     * cannot be set.
      */
     setPropertyByteArray(string propertyName, vec<uint8_t> value )
         generates (Status status);
@@ -366,9 +372,9 @@
      * @param algorithm the algorithm to use. The string conforms to JCA
      * Standard Names for Cipher Transforms and is case insensitive. An
      * example algorithm is "AES/CBC/PKCS5Padding".
-     * @return status the status of the call. The status must be one of
-     * ERROR_DRM_SESSION_NOT_OPENED if the session is not opened,
-     * BAD_VALUE if any parameters are invalid or ERROR_DRM_INVALID_STATE
+     * @return status the status of the call. The status must be OK or one of
+     * the following errors: ERROR_DRM_SESSION_NOT_OPENED if the session is not
+     * opened, BAD_VALUE if any parameters are invalid or ERROR_DRM_INVALID_STATE
      * if the HAL is in a state where the algorithm cannot be set.
      */
     setCipherAlgorithm(SessionId sessionId, string algorithm)
@@ -381,9 +387,9 @@
      * @param algorithm the algorithm to use. The string conforms to JCA
      * Standard Names for Mac Algorithms and is case insensitive. An example MAC
      * algorithm string is "HmacSHA256".
-     * @return status the status of the call. The status must be one of
-     * ERROR_DRM_SESSION_NOT_OPENED if the session is not opened,
-     * BAD_VALUE if any parameters are invalid or ERROR_DRM_INVALID_STATE
+     * @return status the status of the call. The status must be OK or one of the
+     * following errors: ERROR_DRM_SESSION_NOT_OPENED if the session is not
+     * opened, BAD_VALUE if any parameters are invalid or ERROR_DRM_INVALID_STATE
      * if the HAL is in a state where the algorithm cannot be set.
      */
     setMacAlgorithm(SessionId sessionId, string algorithm)
@@ -398,11 +404,10 @@
      * @param keyId the ID of the key to use for encryption
      * @param input the input data to encrypt
      * @param iv the initialization vector to use for encryption
-     * @return status the status of the call. The status must be one of
-     * ERROR_DRM_SESSION_NOT_OPENED if the session is not opened,
+     * @return status the status of the call. The status must be OK or one of the
+     * following errors: ERROR_DRM_SESSION_NOT_OPENED if the session is not opened,
      * BAD_VALUE if any parameters are invalid or ERROR_DRM_INVALID_STATE
-     * if the HAL is in a state where the encrypt operation cannot be
-     * performed.
+     * if the HAL is in a state where the encrypt operation cannot be performed.
      * @return output the decrypted data
      */
     encrypt(SessionId sessionId, vec<uint8_t> keyId, vec<uint8_t> input,
@@ -417,9 +422,9 @@
      * @param keyId the ID of the key to use for decryption
      * @param input the input data to decrypt
      * @param iv the initialization vector to use for decryption
-     * @return status the status of the call. The status must be one of
-     * ERROR_DRM_SESSION_NOT_OPENED if the session is not opened,
-     * BAD_VALUE if any parameters are invalid or ERROR_DRM_INVALID_STATE
+     * @return status the status of the call. The status must be OK or one of
+     * the following errors: ERROR_DRM_SESSION_NOT_OPENED if the session is not
+     * opened, BAD_VALUE if any parameters are invalid or ERROR_DRM_INVALID_STATE
      * if the HAL is in a state where the decrypt operation cannot be
      * performed.
      * @return output the decrypted data
@@ -435,9 +440,9 @@
      * @param sessionId the session id the call applies to
      * @param keyId the ID of the key to use for decryption
      * @param message the message to compute a signature over
-     * @return status the status of the call. The status must be one of
-     * ERROR_DRM_SESSION_NOT_OPENED if the session is not opened,
-     * BAD_VALUE if any parameters are invalid or ERROR_DRM_INVALID_STATE
+     * @return status the status of the call. The status must be OK or one of
+     * the following errors: ERROR_DRM_SESSION_NOT_OPENED if the session is not
+     * opened, BAD_VALUE if any parameters are invalid or ERROR_DRM_INVALID_STATE
      * if the HAL is in a state where the sign operation cannot be
      * performed.
      * @return signature the computed signature
@@ -454,9 +459,9 @@
      * @param keyId the ID of the key to use for decryption
      * @param message the message to compute a hash of
      * @param signature the signature to verify
-     * @return status the status of the call. The status must be one of
-     * ERROR_DRM_SESSION_NOT_OPENED if the session is not opened,
-     * BAD_VALUE if any parameters are invalid or ERROR_DRM_INVALID_STATE
+     * @return status the status of the call. The status must be OK or one of
+     * the following errors: ERROR_DRM_SESSION_NOT_OPENED if the session is not
+     * opened, BAD_VALUE if any parameters are invalid or ERROR_DRM_INVALID_STATE
      * if the HAL is in a state where the verify operation cannot be
      * performed.
      * @return match true if the signature is verified positively,
@@ -475,11 +480,11 @@
      * @param message the message to compute the signature on
      * @param wrappedKey the private key returned during provisioning as
      * returned by provideProvisionResponse.
-     * @return status the status of the call. The status must be one of
-     * ERROR_DRM_SESSION_NOT_OPENED if the session is not opened,
-     * BAD_VALUE if any parameters are invalid or ERROR_DRM_INVALID_STATE
-     * if the HAL is in a state where the signRSA operation cannot be
-     * performed.
+     * @return status the status of the call. The status must be OK or one of
+     * the following errors: ERROR_DRM_SESSION_NOT_OPENED if the session is
+     * not opened, BAD_VALUE if any parameters are invalid or
+     * ERROR_DRM_INVALID_STATE if the HAL is in a state where the signRSA
+     * operation cannot be performed.
      * @return signature the RSA signature computed over the message
      */
     signRSA(SessionId sessionId, string algorithm, vec<uint8_t> message,
diff --git a/drm/drm/1.0/default/DrmFactory.cpp b/drm/drm/1.0/default/DrmFactory.cpp
index 494ca53..f2d4a5a 100644
--- a/drm/drm/1.0/default/DrmFactory.cpp
+++ b/drm/drm/1.0/default/DrmFactory.cpp
@@ -27,7 +27,7 @@
 namespace implementation {
 
     DrmFactory::DrmFactory() :
-        loader("/vendor/lib/mediadrm", "createDrmFactory", "drm") {}
+        loader("/vendor/lib/mediadrm", "createDrmFactory") {}
 
     // Methods from ::android::hardware::drm::drm::V1_0::IDrmFactory follow.
     Return<bool> DrmFactory::isCryptoSchemeSupported (
@@ -40,6 +40,16 @@
         return false;
     }
 
+    Return<bool> DrmFactory::isContentTypeSupported (
+            const hidl_string& mimeType) {
+        for (size_t i = 0; i < loader.factoryCount(); i++) {
+            if (loader.getFactory(i)->isContentTypeSupported(String8(mimeType.c_str()))) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     Return<void> DrmFactory::createPlugin(const hidl_array<uint8_t, 16>& uuid,
             createPlugin_cb _hidl_cb) {
 
diff --git a/drm/drm/1.0/default/DrmFactory.h b/drm/drm/1.0/default/DrmFactory.h
index 4dd9ac0..2b88d00 100644
--- a/drm/drm/1.0/default/DrmFactory.h
+++ b/drm/drm/1.0/default/DrmFactory.h
@@ -47,6 +47,9 @@
     Return<bool> isCryptoSchemeSupported(const hidl_array<uint8_t, 16>& uuid)
             override;
 
+    Return<bool> isContentTypeSupported(const hidl_string &mimeType)
+            override;
+
     Return<void> createPlugin(const hidl_array<uint8_t, 16>& uuid,
             createPlugin_cb _hidl_cb) override;
 
diff --git a/drm/drm/1.0/default/TypeConvert.cpp b/drm/drm/1.0/default/TypeConvert.cpp
index 2b4e2a2..4bed284 100644
--- a/drm/drm/1.0/default/TypeConvert.cpp
+++ b/drm/drm/1.0/default/TypeConvert.cpp
@@ -26,6 +26,9 @@
 Status toStatus(status_t legacyStatus) {
     Status status;
     switch(legacyStatus) {
+    case android::OK:
+        status = Status::OK;
+        break;
     case android::ERROR_DRM_NO_LICENSE:
         status = Status::ERROR_DRM_NO_LICENSE;
         break;
diff --git a/drm/drm/1.0/types.hal b/drm/drm/1.0/types.hal
index 3d77911..e099418 100644
--- a/drm/drm/1.0/types.hal
+++ b/drm/drm/1.0/types.hal
@@ -18,6 +18,12 @@
 
 enum Status : uint32_t {
     /**
+     * The DRM plugin must return OK when an operation completes without any
+     * errors.
+     */
+    OK,
+
+    /**
      * The DRM plugin must return ERROR_DRM_NO_LICENSE, when decryption is
      * attempted and no license keys have been provided.
      */
diff --git a/evs/1.0/default/EvsEnumerator.cpp b/evs/1.0/default/EvsEnumerator.cpp
index 9f38041..ba8da00 100644
--- a/evs/1.0/default/EvsEnumerator.cpp
+++ b/evs/1.0/default/EvsEnumerator.cpp
@@ -62,8 +62,7 @@
     return Void();
 }
 
-Return<void> EvsEnumerator::openCamera(const hidl_string& cameraId,
-                                             openCamera_cb callback) {
+Return<sp<IEvsCamera>> EvsEnumerator::openCamera(const hidl_string& cameraId) {
     ALOGD("openCamera");
 
     // Find the named camera
@@ -78,20 +77,18 @@
 
     if (!pRecord) {
         ALOGE("Requested camera %s not found", cameraId.c_str());
-        callback(nullptr);
+        return nullptr;
     }
     else if (pRecord->inUse) {
         ALOGE("Cannot open camera %s which is already in use", cameraId.c_str());
-        callback(nullptr);
+        return nullptr;
     }
     else {
         /* TODO(b/33492405):  Do this, When HIDL can give us back a recognizable pointer
         pRecord->inUse = true;
          */
-        callback(pRecord->pCamera);
+        return(pRecord->pCamera);
     }
-
-    return Void();
 }
 
 Return<void> EvsEnumerator::closeCamera(const ::android::sp<IEvsCamera>& camera) {
@@ -112,22 +109,20 @@
     return Void();
 }
 
-Return<void> EvsEnumerator::openDisplay(openDisplay_cb callback) {
+Return<sp<IEvsDisplay>> EvsEnumerator::openDisplay() {
     ALOGD("openDisplay");
 
     // If we already have a display active, then this request must be denied
     if (mActiveDisplay != nullptr) {
         ALOGW("Rejecting openDisplay request the display is already in use.");
-        callback(nullptr);
+        return nullptr;
     }
     else {
         // Create a new display interface and return it
         mActiveDisplay = new EvsDisplay();
         ALOGD("Returning new EvsDisplay object %p", mActiveDisplay.get());
-        callback(mActiveDisplay);
+        return mActiveDisplay;
     }
-
-    return Void();
 }
 
 Return<void> EvsEnumerator::closeDisplay(const ::android::sp<IEvsDisplay>& display) {
diff --git a/evs/1.0/default/EvsEnumerator.h b/evs/1.0/default/EvsEnumerator.h
index 69caa17..90df837 100644
--- a/evs/1.0/default/EvsEnumerator.h
+++ b/evs/1.0/default/EvsEnumerator.h
@@ -34,9 +34,9 @@
 public:
     // Methods from ::android::hardware::evs::V1_0::IEvsEnumerator follow.
     Return<void> getCameraList(getCameraList_cb _hidl_cb)  override;
-    Return<void> openCamera(const hidl_string& cameraId, openCamera_cb callback)  override;
+    Return<sp<IEvsCamera>> openCamera(const hidl_string& cameraId) override;
     Return<void> closeCamera(const ::android::sp<IEvsCamera>& carCamera)  override;
-    Return<void> openDisplay(openDisplay_cb callback)  override;
+    Return<sp<IEvsDisplay>> openDisplay()  override;
     Return<void> closeDisplay(const ::android::sp<IEvsDisplay>& display)  override;
 
     // Implementation details
diff --git a/gatekeeper/1.0/vts/functional/gatekeeper_hidl_hal_test.cpp b/gatekeeper/1.0/vts/functional/gatekeeper_hidl_hal_test.cpp
index e919b48..09690f8 100644
--- a/gatekeeper/1.0/vts/functional/gatekeeper_hidl_hal_test.cpp
+++ b/gatekeeper/1.0/vts/functional/gatekeeper_hidl_hal_test.cpp
@@ -85,7 +85,7 @@
       auto ret = gatekeeper_->enroll(
           uid_, req.curPwdHandle, req.curPwd, req.newPwd,
           [&rsp](const GatekeeperResponse &cbRsp) { rsp = cbRsp; });
-      ASSERT_TRUE(ret.getStatus().isOk());
+      ASSERT_TRUE(ret.isOk());
       if (rsp.code != GatekeeperStatusCode::ERROR_RETRY_TIMEOUT) break;
       ALOGI("%s: got retry code; retrying in 1 sec", __func__);
       sleep(1);
@@ -97,7 +97,7 @@
       auto ret = gatekeeper_->verify(
           uid_, req.challenge, req.curPwdHandle, req.newPwd,
           [&rsp](const GatekeeperResponse &cb_rsp) { rsp = cb_rsp; });
-      ASSERT_TRUE(ret.getStatus().isOk());
+      ASSERT_TRUE(ret.isOk());
       if (rsp.code != GatekeeperStatusCode::ERROR_RETRY_TIMEOUT) break;
       ALOGI("%s: got retry code; retrying in 1 sec", __func__);
       sleep(1);
@@ -108,7 +108,7 @@
     while (true) {
       auto ret = gatekeeper_->deleteUser(
           uid_, [&rsp](const GatekeeperResponse &cb_rsp) { rsp = cb_rsp; });
-      ASSERT_TRUE(ret.getStatus().isOk());
+      ASSERT_TRUE(ret.isOk());
       if (rsp.code != GatekeeperStatusCode::ERROR_RETRY_TIMEOUT) break;
       ALOGI("%s: got retry code; retrying in 1 sec", __func__);
       sleep(1);
@@ -119,7 +119,7 @@
     while (true) {
       auto ret = gatekeeper_->deleteAllUsers(
           [&rsp](const GatekeeperResponse &cb_rsp) { rsp = cb_rsp; });
-      ASSERT_TRUE(ret.getStatus().isOk());
+      ASSERT_TRUE(ret.isOk());
       if (rsp.code != GatekeeperStatusCode::ERROR_RETRY_TIMEOUT) break;
       ALOGI("%s: got retry code; retrying in 1 sec", __func__);
       sleep(1);
diff --git a/gnss/1.0/default/Android.mk b/gnss/1.0/default/Android.mk
index 06ef331..6289491 100644
--- a/gnss/1.0/default/Android.mk
+++ b/gnss/1.0/default/Android.mk
@@ -27,3 +27,27 @@
     libhardware
 
 include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_MODULE := android.hardware.gnss@1.0-service
+LOCAL_INIT_RC := android.hardware.gnss@1.0-service.rc
+LOCAL_SRC_FILES := \
+    service.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+    liblog \
+    libcutils \
+    libdl \
+    libbase \
+    libutils \
+    libhardware_legacy \
+    libhardware \
+
+LOCAL_SHARED_LIBRARIES += \
+    libhwbinder \
+    libhidlbase \
+    libhidltransport \
+    android.hardware.gnss@1.0 \
+
+include $(BUILD_EXECUTABLE)
diff --git a/gnss/1.0/default/Gnss.cpp b/gnss/1.0/default/Gnss.cpp
index 66be37e..5e6e65d 100644
--- a/gnss/1.0/default/Gnss.cpp
+++ b/gnss/1.0/default/Gnss.cpp
@@ -385,7 +385,7 @@
                                           preferredTimeMs) == 0);
 }
 
-Return<void> Gnss::getExtensionAGnssRil(getExtensionAGnssRil_cb _hidl_cb)  {
+Return<sp<IAGnssRil>> Gnss::getExtensionAGnssRil()  {
     if (mGnssIface == nullptr) {
         ALOGE("%s: Gnss interface is unavailable", __func__);
     } else {
@@ -397,11 +397,10 @@
             mGnssRil = new AGnssRil(agpsRilIface);
         }
     }
-    _hidl_cb(mGnssRil);
-    return Void();
+    return mGnssRil;
 }
 
-Return<void> Gnss::getExtensionGnssConfiguration(getExtensionGnssConfiguration_cb _hidl_cb)  {
+Return<sp<IGnssConfiguration>> Gnss::getExtensionGnssConfiguration()  {
     if (mGnssIface == nullptr) {
         ALOGE("%s: Gnss interface is unavailable", __func__);
     } else {
@@ -415,10 +414,9 @@
             mGnssConfig = new GnssConfiguration(gnssConfigIface);
         }
     }
-    _hidl_cb(mGnssConfig);
-    return Void();
+    return mGnssConfig;
 }
-Return<void> Gnss::getExtensionGnssGeofencing(getExtensionGnssGeofencing_cb _hidl_cb)  {
+Return<sp<IGnssGeofencing>> Gnss::getExtensionGnssGeofencing()  {
     if (mGnssIface == nullptr) {
         ALOGE("%s: Gnss interface is unavailable", __func__);
     } else {
@@ -433,11 +431,10 @@
         }
     }
 
-    _hidl_cb(mGnssGeofencingIface);
-    return Void();
+    return mGnssGeofencingIface;
 }
 
-Return<void> Gnss::getExtensionAGnss(getExtensionAGnss_cb _hidl_cb)  {
+Return<sp<IAGnss>> Gnss::getExtensionAGnss()  {
     if (mGnssIface == nullptr) {
         ALOGE("%s: Gnss interface is unavailable", __func__);
     } else {
@@ -449,11 +446,10 @@
             mAGnssIface = new AGnss(agpsIface);
         }
     }
-    _hidl_cb(mAGnssIface);
-    return Void();
+    return mAGnssIface;
 }
 
-Return<void> Gnss::getExtensionGnssNi(getExtensionGnssNi_cb _hidl_cb)  {
+Return<sp<IGnssNi>> Gnss::getExtensionGnssNi()  {
     if (mGnssIface == nullptr) {
         ALOGE("%s: Gnss interface is unavailable", __func__);
     } else {
@@ -465,11 +461,10 @@
             mGnssNi = new GnssNi(gpsNiIface);
         }
     }
-    _hidl_cb(mGnssNi);
-    return Void();
+    return mGnssNi;
 }
 
-Return<void> Gnss::getExtensionGnssMeasurement(getExtensionGnssMeasurement_cb _hidl_cb) {
+Return<sp<IGnssMeasurement>> Gnss::getExtensionGnssMeasurement() {
     if (mGnssIface == nullptr) {
         ALOGE("%s: Gnss interface is unavailable", __func__);
     } else {
@@ -483,12 +478,10 @@
             mGnssMeasurement = new GnssMeasurement(gpsMeasurementIface);
         }
     }
-    _hidl_cb(mGnssMeasurement);
-    return Void();
+    return mGnssMeasurement;
 }
 
-Return<void> Gnss::getExtensionGnssNavigationMessage(
-        getExtensionGnssNavigationMessage_cb _hidl_cb) {
+Return<sp<IGnssNavigationMessage>> Gnss::getExtensionGnssNavigationMessage() {
     if (mGnssIface == nullptr) {
         ALOGE("%s: Gnss interface is unavailable", __func__);
     } else {
@@ -504,11 +497,10 @@
         }
     }
 
-    _hidl_cb(mGnssNavigationMessage);
-    return Void();
+    return mGnssNavigationMessage;
 }
 
-Return<void> Gnss::getExtensionXtra(getExtensionXtra_cb _hidl_cb)  {
+Return<sp<IGnssXtra>> Gnss::getExtensionXtra()  {
     if (mGnssIface == nullptr) {
         ALOGE("%s: Gnss interface is unavailable", __func__);
     } else {
@@ -522,11 +514,10 @@
         }
     }
 
-    _hidl_cb(mGnssXtraIface);
-    return Void();
+    return mGnssXtraIface;
 }
 
-Return<void> Gnss::getExtensionGnssDebug(getExtensionGnssDebug_cb _hidl_cb)  {
+Return<sp<IGnssDebug>> Gnss::getExtensionGnssDebug()  {
     if (mGnssIface == nullptr) {
         ALOGE("%s: Gnss interface is unavailable", __func__);
     } else {
@@ -540,8 +531,7 @@
         }
     }
 
-    _hidl_cb(mGnssDebug);
-    return Void();
+    return mGnssDebug;
 }
 
 IGnss* HIDL_FETCH_IGnss(const char* hal) {
diff --git a/gnss/1.0/default/Gnss.h b/gnss/1.0/default/Gnss.h
index a2c8676..e12ac12 100644
--- a/gnss/1.0/default/Gnss.h
+++ b/gnss/1.0/default/Gnss.h
@@ -74,16 +74,15 @@
                                  uint32_t minIntervalMs,
                                  uint32_t preferredAccuracyMeters,
                                  uint32_t preferredTimeMs)  override;
-    Return<void> getExtensionAGnssRil(getExtensionAGnssRil_cb _hidl_cb) override;
-    Return<void> getExtensionGnssGeofencing(getExtensionGnssGeofencing_cb _hidl_cb)  override;
-    Return<void> getExtensionAGnss(getExtensionAGnss_cb _hidl_cb)  override;
-    Return<void> getExtensionGnssNi(getExtensionGnssNi_cb _hidl_cb)  override;
-    Return<void> getExtensionGnssMeasurement(getExtensionGnssMeasurement_cb _hidl_cb)  override;
-    Return<void> getExtensionGnssNavigationMessage(
-        getExtensionGnssNavigationMessage_cb _hidl_cb)  override;
-    Return<void> getExtensionXtra(getExtensionXtra_cb _hidl_cb)  override;
-    Return<void> getExtensionGnssDebug(getExtensionGnssDebug_cb _hidl_cb)  override;
-    Return<void> getExtensionGnssConfiguration(getExtensionGnssConfiguration_cb _hidl_cb) override;
+    Return<sp<IAGnssRil>> getExtensionAGnssRil() override;
+    Return<sp<IGnssGeofencing>> getExtensionGnssGeofencing() override;
+    Return<sp<IAGnss>> getExtensionAGnss() override;
+    Return<sp<IGnssNi>> getExtensionGnssNi() override;
+    Return<sp<IGnssMeasurement>> getExtensionGnssMeasurement() override;
+    Return<sp<IGnssNavigationMessage>> getExtensionGnssNavigationMessage() override;
+    Return<sp<IGnssXtra>> getExtensionXtra() override;
+    Return<sp<IGnssConfiguration>> getExtensionGnssConfiguration() override;
+    Return<sp<IGnssDebug>> getExtensionGnssDebug() override;
 
     /*
      * Callback methods to be passed into the conventional GNSS HAL by the default
diff --git a/gnss/1.0/default/android.hardware.gnss@1.0-service.rc b/gnss/1.0/default/android.hardware.gnss@1.0-service.rc
new file mode 100644
index 0000000..eeb2e43
--- /dev/null
+++ b/gnss/1.0/default/android.hardware.gnss@1.0-service.rc
@@ -0,0 +1,4 @@
+service gnss_service /system/bin/hw/android.hardware.gnss@1.0-service
+    class main
+    user system
+    group system
diff --git a/gnss/1.0/default/service.cpp b/gnss/1.0/default/service.cpp
new file mode 100644
index 0000000..4e040c5
--- /dev/null
+++ b/gnss/1.0/default/service.cpp
@@ -0,0 +1,12 @@
+#define LOG_TAG "android.hardware.gnss@1.0-service"
+
+#include <android/hardware/gnss/1.0/IGnss.h>
+
+#include <hidl/LegacySupport.h>
+
+using android::hardware::gnss::V1_0::IGnss;
+using android::hardware::defaultPassthroughServiceImplementation;
+
+int main() {
+    return defaultPassthroughServiceImplementation<IGnss>("gnss");
+}
diff --git a/graphics/allocator/2.0/vts/functional/graphics_allocator_hidl_hal_test.cpp b/graphics/allocator/2.0/vts/functional/graphics_allocator_hidl_hal_test.cpp
index 22131ee..a0443d6 100644
--- a/graphics/allocator/2.0/vts/functional/graphics_allocator_hidl_hal_test.cpp
+++ b/graphics/allocator/2.0/vts/functional/graphics_allocator_hidl_hal_test.cpp
@@ -129,7 +129,7 @@
     }
   });
 
-  ASSERT_TRUE(ret.getStatus().isOk());
+  ASSERT_TRUE(ret.isOk());
 }
 
 TEST_F(GraphicsAllocatorHidlTest, DumpDebugInfo) {
@@ -137,7 +137,7 @@
     // nothing to do
   });
 
-  ASSERT_TRUE(ret.getStatus().isOk());
+  ASSERT_TRUE(ret.isOk());
 }
 
 TEST_F(GraphicsAllocatorHidlTest, CreateDestroyDescriptor) {
@@ -150,11 +150,11 @@
         descriptor = tmpDescriptor;
       });
 
-  ASSERT_TRUE(ret.getStatus().isOk());
+  ASSERT_TRUE(ret.isOk());
   ASSERT_EQ(Error::NONE, error);
 
   auto err_ret = mClient->destroyDescriptor(descriptor);
-  ASSERT_TRUE(err_ret.getStatus().isOk());
+  ASSERT_TRUE(err_ret.isOk());
   ASSERT_EQ(Error::NONE, static_cast<Error>(err_ret));
 }
 
@@ -172,7 +172,7 @@
   descriptors[0] = descriptor;
 
   auto ret = mClient->testAllocate(descriptors);
-  ASSERT_TRUE(ret.getStatus().isOk());
+  ASSERT_TRUE(ret.isOk());
 
   auto error = static_cast<Error>(ret);
   ASSERT_TRUE(error == Error::NONE || error == Error::NOT_SHARED);
@@ -193,7 +193,7 @@
   descriptors[1] = descriptor;
 
   auto ret = mClient->testAllocate(descriptors);
-  ASSERT_TRUE(ret.getStatus().isOk());
+  ASSERT_TRUE(ret.isOk());
 
   auto error = static_cast<Error>(ret);
   ASSERT_TRUE(error == Error::NONE || error == Error::NOT_SHARED);
@@ -218,13 +218,13 @@
         buffers = tmpBuffers;
       });
 
-  ASSERT_TRUE(ret.getStatus().isOk());
+  ASSERT_TRUE(ret.isOk());
   ASSERT_TRUE(error == Error::NONE || error == Error::NOT_SHARED);
   EXPECT_EQ(1u, buffers.size());
 
   if (!buffers.empty()) {
     auto err_ret = mClient->free(buffers[0]);
-    EXPECT_TRUE(err_ret.getStatus().isOk());
+    EXPECT_TRUE(err_ret.isOk());
     EXPECT_EQ(Error::NONE, static_cast<Error>(err_ret));
   }
 }
@@ -253,13 +253,13 @@
         buffers = tmpBuffers;
       });
 
-  ASSERT_TRUE(ret.getStatus().isOk());
+  ASSERT_TRUE(ret.isOk());
   ASSERT_TRUE(error == Error::NONE || error == Error::NOT_SHARED);
   EXPECT_EQ(descriptors.size(), buffers.size());
 
   for (auto buf : buffers) {
     auto err_ret = mClient->free(buf);
-    EXPECT_TRUE(err_ret.getStatus().isOk());
+    EXPECT_TRUE(err_ret.isOk());
     EXPECT_EQ(Error::NONE, static_cast<Error>(err_ret));
   }
 }
@@ -280,18 +280,18 @@
         buffers = tmpBuffers;
       });
 
-  ASSERT_TRUE(ret.getStatus().isOk());
+  ASSERT_TRUE(ret.isOk());
   ASSERT_TRUE(error == Error::NONE || error == Error::NOT_SHARED);
   ASSERT_EQ(1u, buffers.size());
 
   ret = mClient->exportHandle(
       descriptors[0], buffers[0],
       [&](const auto& tmpError, const auto&) { error = tmpError; });
-  EXPECT_TRUE(ret.getStatus().isOk());
+  EXPECT_TRUE(ret.isOk());
   EXPECT_EQ(Error::NONE, error);
 
   auto err_ret = mClient->free(buffers[0]);
-  EXPECT_TRUE(err_ret.getStatus().isOk());
+  EXPECT_TRUE(err_ret.isOk());
   EXPECT_EQ(Error::NONE, static_cast<Error>(err_ret));
 }
 
diff --git a/light/2.0/vts/functional/light_hidl_hal_test.cpp b/light/2.0/vts/functional/light_hidl_hal_test.cpp
index 9912079..9b9f543 100644
--- a/light/2.0/vts/functional/light_hidl_hal_test.cpp
+++ b/light/2.0/vts/functional/light_hidl_hal_test.cpp
@@ -36,8 +36,8 @@
 
 #define LIGHT_SERVICE_NAME "light"
 
-#define ASSERT_OK(ret) ASSERT_TRUE(ret.getStatus().isOk())
-#define EXPECT_OK(ret) EXPECT_TRUE(ret.getStatus().isOk())
+#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk())
+#define EXPECT_OK(ret) EXPECT_TRUE(ret.isOk())
 
 class LightHidlTest : public ::testing::Test {
 public:
diff --git a/light/2.0/vts/functional/vts/testcases/hal/light/hidl/target/AndroidTest.xml b/light/2.0/vts/functional/vts/testcases/hal/light/hidl/target/AndroidTest.xml
index 240f1f0..94a942b 100644
--- a/light/2.0/vts/functional/vts/testcases/hal/light/hidl/target/AndroidTest.xml
+++ b/light/2.0/vts/functional/vts/testcases/hal/light/hidl/target/AndroidTest.xml
@@ -24,6 +24,7 @@
             _32bit::DATA/nativetest/light_hidl_hal_test/light_hidl_hal_test,
             _64bit::DATA/nativetest64/light_hidl_hal_test/light_hidl_hal_test,
             "/>
+        <option name="test-config-path" value="vts/testcases/hal/light/hidl/target/HalLightHidlTargetBasicTest.config" />
         <option name="binary-test-type" value="gtest" />
         <option name="test-timeout" value="1m" />
     </test>
diff --git a/light/2.0/vts/functional/vts/testcases/hal/light/hidl/target/HalLightHidlTargetBasicTest.config b/light/2.0/vts/functional/vts/testcases/hal/light/hidl/target/HalLightHidlTargetBasicTest.config
new file mode 100644
index 0000000..cb572aa
--- /dev/null
+++ b/light/2.0/vts/functional/vts/testcases/hal/light/hidl/target/HalLightHidlTargetBasicTest.config
@@ -0,0 +1,33 @@
+{
+    "coverage": true,
+    "modules": [
+        {
+            "module_name": "system/lib64/hw/lights.bullhead",
+            "git_project": {
+                "name": "device/lge/bullhead",
+                "path": "device/lge/bullhead"
+            }
+        },
+        {
+            "module_name": "system/lib64/hw/lights.marlin",
+            "git_project": {
+                "name": "device/google/marlin",
+                "path": "device/google/marlin"
+            }
+        },
+        {
+            "module_name": "system/lib64/hw/lights.sailfish",
+            "git_project": {
+                "name": "device/google/marlin",
+                "path": "device/google/marlin"
+            }
+        },
+        {
+            "module_name": "system/lib64/hw/android.hardware.light@2.0-impl",
+            "git_project": {
+                "name": "platform/hardware/interfaces",
+                "path": "hardware/interfaces"
+            }
+        }
+    ]
+}
diff --git a/nfc/1.0/vts/functional/vts/testcases/hal/nfc/hidl/host/NfcHidlBasicTest.py b/nfc/1.0/vts/functional/vts/testcases/hal/nfc/hidl/host/NfcHidlBasicTest.py
index 136704a..de01f43 100644
--- a/nfc/1.0/vts/functional/vts/testcases/hal/nfc/hidl/host/NfcHidlBasicTest.py
+++ b/nfc/1.0/vts/functional/vts/testcases/hal/nfc/hidl/host/NfcHidlBasicTest.py
@@ -47,13 +47,14 @@
             self.dut.shell.one.Execute(
                 "setprop vts.hal.vts.hidl.get_stub false")
 
-        self.dut.hal.InitHidlHal(target_type="nfc",
-                                 target_basepaths=["/system/lib64"],
-                                 target_version=1.0,
-                                 target_package="android.hardware.nfc",
-                                 target_component_name="INfc",
-                                 hw_binder_service_name="nfc_nci",
-                                 bits=64)
+        self.dut.hal.InitHidlHal(
+            target_type="nfc",
+            target_basepaths=self.dut.libPaths,
+            target_version=1.0,
+            target_package="android.hardware.nfc",
+            target_component_name="INfc",
+            hw_binder_service_name="nfc_nci",
+            bits=64 if self.dut.is64Bit else 32)
 
     def tearDownClass(self):
         """Turns off the framework-layer NFC service."""
diff --git a/power/1.0/vts/functional/power_hidl_hal_test.cpp b/power/1.0/vts/functional/power_hidl_hal_test.cpp
index 045a34b..36bdb0a 100644
--- a/power/1.0/vts/functional/power_hidl_hal_test.cpp
+++ b/power/1.0/vts/functional/power_hidl_hal_test.cpp
@@ -49,10 +49,10 @@
   Return<void> ret;
 
   ret = power->setInteractive(true);
-  ASSERT_TRUE(ret.getStatus().isOk());
+  ASSERT_TRUE(ret.isOk());
 
   ret = power->setInteractive(false);
-  ASSERT_TRUE(ret.getStatus().isOk());
+  ASSERT_TRUE(ret.isOk());
 }
 
 // Sanity check Power::powerHint on good and bad inputs.
@@ -66,10 +66,10 @@
   Return<void> ret;
   for (auto hint : hints) {
     ret = power->powerHint(hint, 1);
-    ASSERT_TRUE(ret.getStatus().isOk());
+    ASSERT_TRUE(ret.isOk());
 
     ret = power->powerHint(hint, 0);
-    ASSERT_TRUE(ret.getStatus().isOk());
+    ASSERT_TRUE(ret.isOk());
   }
 }
 
@@ -77,15 +77,15 @@
 TEST_F(PowerHidlTest, SetFeature) {
   Return<void> ret;
   ret = power->setFeature(Feature::POWER_FEATURE_DOUBLE_TAP_TO_WAKE, true);
-  ASSERT_TRUE(ret.getStatus().isOk());
+  ASSERT_TRUE(ret.isOk());
   ret = power->setFeature(Feature::POWER_FEATURE_DOUBLE_TAP_TO_WAKE, false);
-  ASSERT_TRUE(ret.getStatus().isOk());
+  ASSERT_TRUE(ret.isOk());
 
   Feature badFeature = static_cast<Feature>(0x2);
   ret = power->setFeature(badFeature, true);
-  ASSERT_TRUE(ret.getStatus().isOk());
+  ASSERT_TRUE(ret.isOk());
   ret = power->setFeature(badFeature, false);
-  ASSERT_TRUE(ret.getStatus().isOk());
+  ASSERT_TRUE(ret.isOk());
 }
 
 // Sanity check Power::getPlatformLowPowerStats().
@@ -98,7 +98,7 @@
     s = status;
   };
   Return<void> ret = power->getPlatformLowPowerStats(cb);
-  ASSERT_TRUE(ret.getStatus().isOk());
+  ASSERT_TRUE(ret.isOk());
   ASSERT_TRUE(s == Status::SUCCESS || s == Status::FILESYSTEM_ERROR);
 }
 
diff --git a/radio/1.0/types.hal b/radio/1.0/types.hal
index 8c7f538..49ba30e 100644
--- a/radio/1.0/types.hal
+++ b/radio/1.0/types.hal
@@ -51,7 +51,6 @@
 };
 
 enum RadioError : int32_t {
-    INVALID_RESPONSE = -1,                // Response from vendor had invalid data
     NONE = 0,                             // Success
     RADIO_NOT_AVAILABLE = 1,              // If radio did not start or is resetting
     GENERIC_FAILURE = 2,
@@ -115,7 +114,8 @@
     NO_NETWORK_FOUND = 63,                // Network cannot be found
     DEVICE_IN_USE = 64,                   // Operation cannot be performed because the device
                                           // is currently in use
-    RIL_E_ABORTED = 65,                   // Operation aborted
+    ABORTED = 65,                         // Operation aborted
+    INVALID_RESPONSE = 66,                // Response from vendor had invalid data
 
     // TODO(May be moved to vendor HAL extension)
     // OEM specific error codes. To be used by OEM when they don't want to reveal
@@ -1089,8 +1089,7 @@
     int32_t gsmUmtsSubscriptionAppIndex;  // value < RadioConst:CARD_MAX_APPS, -1 if none
     int32_t cdmaSubscriptionAppIndex;     // value < RadioConst:CARD_MAX_APPS, -1 if none
     int32_t imsSubscriptionAppIndex;      // value < RadioConst:CARD_MAX_APPS, -1 if none
-    int32_t numApplications;              // value <= RadioConst:CARD_MAX_APPS
-    AppStatus[RadioConst:CARD_MAX_APPS] applications;
+    vec<AppStatus> applications;          // size <= RadioConst:CARD_MAX_APPS
 };
 
 /*
diff --git a/sensors/1.0/vts/functional/vts/testcases/hal/sensors/hidl/host/SensorsHidlTest.py b/sensors/1.0/vts/functional/vts/testcases/hal/sensors/hidl/host/SensorsHidlTest.py
index 88fe675..de764af 100644
--- a/sensors/1.0/vts/functional/vts/testcases/hal/sensors/hidl/host/SensorsHidlTest.py
+++ b/sensors/1.0/vts/functional/vts/testcases/hal/sensors/hidl/host/SensorsHidlTest.py
@@ -48,11 +48,11 @@
 
         self.dut.hal.InitHidlHal(
             target_type="sensors",
-            target_basepaths=["/system/lib64"],
+            target_basepaths=self.dut.libPaths,
             target_version=1.0,
             target_package="android.hardware.sensors",
             target_component_name="ISensors",
-            bits=64)
+            bits=64 if self.dut.is64Bit else 32)
 
     def tearDownClass(self):
         """ If profiling is enabled for the test, collect the profiling data
diff --git a/soundtrigger/2.0/vts/functional/soundtrigger_hidl_hal_test.cpp b/soundtrigger/2.0/vts/functional/soundtrigger_hidl_hal_test.cpp
index e5bf086..3379d93 100644
--- a/soundtrigger/2.0/vts/functional/soundtrigger_hidl_hal_test.cpp
+++ b/soundtrigger/2.0/vts/functional/soundtrigger_hidl_hal_test.cpp
@@ -104,7 +104,7 @@
       halProperties = res;
   });
 
-  EXPECT_EQ(Status::EX_NONE, hidlReturn.getStatus().exceptionCode());
+  EXPECT_TRUE(hidlReturn.isOk());
   EXPECT_EQ(0, ret);
   EXPECT_GT(halProperties.maxSoundModels, 0u);
   EXPECT_GT(halProperties.maxKeyPhrases, 0u);
@@ -136,7 +136,7 @@
       handle = res;
   });
 
-  EXPECT_EQ(Status::EX_NONE, hidlReturn.getStatus().exceptionCode());
+  EXPECT_TRUE(hidlReturn.isOk());
   EXPECT_NE(0, ret);
 }
 
@@ -154,7 +154,7 @@
 
   hidlReturn = mSoundTriggerHal->unloadSoundModel(halHandle);
 
-  EXPECT_EQ(Status::EX_NONE, hidlReturn.getStatus().exceptionCode());
+  EXPECT_TRUE(hidlReturn.isOk());
   EXPECT_NE(0, hidlReturn);
 }
 
@@ -184,7 +184,7 @@
 
     hidlReturn = mSoundTriggerHal->startRecognition(handle, config, mCallback, 0);
 
-    EXPECT_EQ(Status::EX_NONE, hidlReturn.getStatus().exceptionCode());
+    EXPECT_TRUE(hidlReturn.isOk());
     EXPECT_NE(0, hidlReturn);
 }
 
@@ -202,7 +202,7 @@
 
     hidlReturn = mSoundTriggerHal->stopRecognition(handle);
 
-    EXPECT_EQ(Status::EX_NONE, hidlReturn.getStatus().exceptionCode());
+    EXPECT_TRUE(hidlReturn.isOk());
     EXPECT_NE(0, hidlReturn);
 }
 
@@ -219,7 +219,7 @@
 
     hidlReturn = mSoundTriggerHal->stopAllRecognitions();
 
-    EXPECT_EQ(Status::EX_NONE, hidlReturn.getStatus().exceptionCode());
+    EXPECT_TRUE(hidlReturn.isOk());
     EXPECT_TRUE(hidlReturn == 0 || hidlReturn == -ENOSYS);
 }
 
diff --git a/tests/bar/1.0/default/Bar.cpp b/tests/bar/1.0/default/Bar.cpp
index 4152bb9..16c0235 100644
--- a/tests/bar/1.0/default/Bar.cpp
+++ b/tests/bar/1.0/default/Bar.cpp
@@ -165,10 +165,8 @@
     return Void();
 }
 
-Return<void> Bar::haveAInterface(const sp<ISimple> &in,
-            haveAInterface_cb _hidl_cb) {
-    _hidl_cb(in);
-    return Void();
+Return<sp<ISimple>> Bar::haveAInterface(const sp<ISimple> &in) {
+    return in;
 }
 
 
diff --git a/tests/bar/1.0/default/Bar.h b/tests/bar/1.0/default/Bar.h
index 70bffe7..b276823 100644
--- a/tests/bar/1.0/default/Bar.h
+++ b/tests/bar/1.0/default/Bar.h
@@ -71,8 +71,7 @@
 
     Return<void> takeAMask(BitField bf, uint8_t first, const MyMask& second, uint8_t third,
             takeAMask_cb _hidl_cb) override;
-    Return<void> haveAInterface(const sp<ISimple> &in,
-            haveAInterface_cb _hidl_cb) override;
+    Return<sp<ISimple>> haveAInterface(const sp<ISimple> &in);
 
 private:
     sp<IFoo> mFoo;
diff --git a/tests/foo/1.0/default/Android.bp b/tests/foo/1.0/default/Android.bp
index 76a4656..952f25d 100644
--- a/tests/foo/1.0/default/Android.bp
+++ b/tests/foo/1.0/default/Android.bp
@@ -5,7 +5,6 @@
     relative_install_path: "hw",
     srcs: [
         "Foo.cpp",
-        "FooCallback.cpp",
     ],
 
     shared_libs: [
diff --git a/tests/foo/1.0/default/Foo.cpp b/tests/foo/1.0/default/Foo.cpp
index cdfdecc..a860ce7 100644
--- a/tests/foo/1.0/default/Foo.cpp
+++ b/tests/foo/1.0/default/Foo.cpp
@@ -2,7 +2,6 @@
 #define LOG_TAG "hidl_test"
 
 #include "Foo.h"
-#include "FooCallback.h"
 #include <android-base/logging.h>
 #include <hidl-test/FooHelper.h>
 #include <inttypes.h>
diff --git a/tests/foo/1.0/default/FooCallback.cpp b/tests/foo/1.0/default/FooCallback.cpp
deleted file mode 100644
index ff3a545..0000000
--- a/tests/foo/1.0/default/FooCallback.cpp
+++ /dev/null
@@ -1,134 +0,0 @@
-
-#define LOG_TAG "hidl_test"
-
-#include "FooCallback.h"
-#include <android/log.h>
-#include <hidl-test/FooHelper.h>
-#include <inttypes.h>
-#include <utils/Timers.h>
-
-namespace android {
-namespace hardware {
-namespace tests {
-namespace foo {
-namespace V1_0 {
-namespace implementation {
-
-enum {
-    NOT_REPORTED = -1LL
-};
-
-FooCallback::FooCallback()
-        : mLock{}, mCond{} {
-    for (size_t i = 0; i < invokeInfo.size(); i++) {
-        invokeInfo[i].invoked = false;
-        invokeInfo[i].timeNs = NOT_REPORTED;
-        invokeInfo[i].callerBlockedNs = NOT_REPORTED;
-    }
-}
-
-Return<void> FooCallback::heyItsYou(
-        const sp<IFooCallback> &_cb) {
-    nsecs_t start = systemTime();
-    ALOGI("SERVER(FooCallback) 1: heyItsYou cb = %p", _cb.get());
-    nsecs_t end = systemTime();
-    {
-        Mutex::Autolock lock(mLock);
-        invokeInfo[0].invoked = true;
-        invokeInfo[0].timeNs = end - start;
-        mCond.signal();
-    }
-    ALOGI("SERVER(FooCallback) 2: heyItsYou returned");
-    return Void();
-}
-
-Return<bool> FooCallback::heyItsYouIsntIt(const sp<IFooCallback> &_cb) {
-    nsecs_t start = systemTime();
-    ALOGI("SERVER(FooCallback) 3: heyItsYouIsntIt cb = %p sleeping for %" PRId64 " seconds", _cb.get(), DELAY_S);
-    sleep(DELAY_S);
-    ALOGI("SERVER(FooCallback) 4: heyItsYouIsntIt cb = %p responding", _cb.get());
-    nsecs_t end = systemTime();
-    {
-        Mutex::Autolock lock(mLock);
-        invokeInfo[1].invoked = true;
-        invokeInfo[1].timeNs = end - start;
-        mCond.signal();
-    }
-    ALOGI("SERVER(FooCallback) 5: heyItsYouIsntIt cb = %p responding", _cb.get());
-    return true;
-}
-
-Return<void> FooCallback::heyItsTheMeaningOfLife(uint8_t tmol) {
-    nsecs_t start = systemTime();
-    ALOGI("SERVER(FooCallback) 6.1: heyItsTheMeaningOfLife = %d sleeping for %" PRId64 " seconds", tmol, DELAY_S);
-    sleep(DELAY_S);
-    ALOGI("SERVER(FooCallback) 6.2: heyItsTheMeaningOfLife = %d done sleeping", tmol);
-    nsecs_t end = systemTime();
-    {
-        Mutex::Autolock lock(mLock);
-        invokeInfo[2].invoked = true;
-        invokeInfo[2].timeNs = end - start;
-        mCond.signal();
-    }
-    ALOGI("SERVER(FooCallback) 6.3: heyItsTheMeaningOfLife returned");
-    return Void();
-}
-
-Return<void> FooCallback::reportResults(int64_t ns, reportResults_cb cb) {
-    ALOGI("SERVER(FooCallback) 8.1: reportResults(%" PRId64 " seconds)", nanoseconds_to_seconds(ns));
-    nsecs_t leftToWaitNs = ns;
-    bool cond;
-    {
-        Mutex::Autolock lock(mLock);
-        while ((cond = ((!invokeInfo[0].invoked ||
-                !invokeInfo[1].invoked ||
-                !invokeInfo[2].invoked ||
-                invokeInfo[0].callerBlockedNs == NOT_REPORTED ||
-                invokeInfo[1].callerBlockedNs == NOT_REPORTED ||
-                invokeInfo[2].callerBlockedNs == NOT_REPORTED)   &&
-               leftToWaitNs > 0))) {
-            nsecs_t start = systemTime();
-            ::android::status_t rc = mCond.waitRelative(mLock, leftToWaitNs);
-            if (rc != ::android::OK) {
-                ALOGW("SERVER(FooCallback)::reportResults(%" PRId64 " ns) Condition::waitRelative(%" PRId64 ") returned error (%d)", ns, leftToWaitNs, rc);
-                if (rc == -ETIMEDOUT) {
-                    // time's up
-                    leftToWaitNs = -1;
-                }
-                break;
-            }
-            ALOGI("SERVER(FooCallback)::reportResults(%" PRId64 " ns) Condition::waitRelative was signalled", ns);
-            leftToWaitNs -= systemTime() - start;
-        }
-    }
-    ALOGI("SERVER(FooCallback) 8.2: reportResults returned;"
-            "invoked? %d, %d, %d; leftToWaitNs = %" PRId64 "; cond = %d",
-            invokeInfo[0].invoked, invokeInfo[1].invoked, invokeInfo[2].invoked,
-            leftToWaitNs, cond);
-    cb(leftToWaitNs, invokeInfo);
-    return Void();
-}
-
-Return<void> FooCallback::youBlockedMeFor(const hidl_array<int64_t, 3> &ns) {
-    ALOGI("SERVER(FooCallback) 7.1: youBlockedMeFor");
-    {
-        Mutex::Autolock lock(mLock);
-        for (size_t i = 0; i < 3; i++) {
-            invokeInfo[i].callerBlockedNs = ns[i];
-        }
-        mCond.signal();
-    }
-    ALOGI("SERVER(FooCallback) 7.2: returned");
-    return Void();
-}
-
-IFooCallback* HIDL_FETCH_IFooCallback(const char* /* name */) {
-    return new FooCallback();
-}
-
-} // namespace implementation
-}  // namespace V1_0
-}  // namespace foo
-}  // namespace tests
-}  // namespace hardware
-}  // namespace android
diff --git a/tests/foo/1.0/default/FooCallback.h b/tests/foo/1.0/default/FooCallback.h
deleted file mode 100644
index 3164a9d..0000000
--- a/tests/foo/1.0/default/FooCallback.h
+++ /dev/null
@@ -1,46 +0,0 @@
-#ifndef ANDROID_HARDWARE_TESTS_FOO_V1_0_FOOCALLBACK_H
-#define ANDROID_HARDWARE_TESTS_FOO_V1_0_FOOCALLBACK_H
-
-#include <android/hardware/tests/foo/1.0/IFooCallback.h>
-#include <hidl/Status.h>
-#include <hidl/MQDescriptor.h>
-
-#include <utils/Condition.h>
-namespace android {
-namespace hardware {
-namespace tests {
-namespace foo {
-namespace V1_0 {
-namespace implementation {
-
-using ::android::hardware::tests::foo::V1_0::IFooCallback;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::hidl_string;
-using ::android::sp;
-
-struct FooCallback : public IFooCallback {
-    FooCallback();
-    // Methods from ::android::hardware::tests::foo::V1_0::IFooCallback follow.
-    Return<void> heyItsYou(const sp<IFooCallback>& cb)  override;
-    Return<bool> heyItsYouIsntIt(const sp<IFooCallback>& cb)  override;
-    Return<void> heyItsTheMeaningOfLife(uint8_t tmol)  override;
-    Return<void> reportResults(int64_t ns, reportResults_cb _hidl_cb)  override;
-    Return<void> youBlockedMeFor(const hidl_array<int64_t, 3 /* 3 */>& callerBlockedInfo)  override;
-
-    hidl_array<InvokeInfo, 3> invokeInfo;
-    Mutex mLock;
-    Condition mCond;
-};
-
-extern "C" IFooCallback* HIDL_FETCH_IFooCallback(const char* name);
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace foo
-}  // namespace tests
-}  // namespace hardware
-}  // namespace android
-
-#endif  // ANDROID_HARDWARE_TESTS_FOO_V1_0_FOOCALLBACK_H
diff --git a/tests/inheritance/1.0/default/Fetcher.cpp b/tests/inheritance/1.0/default/Fetcher.cpp
index f3b576b..7094f07 100644
--- a/tests/inheritance/1.0/default/Fetcher.cpp
+++ b/tests/inheritance/1.0/default/Fetcher.cpp
@@ -17,8 +17,7 @@
     CHECK(!mPrecious->isRemote());
 }
 
-template <typename CB>
-Return<void> selectService(bool sendRemote, CB &_hidl_cb, sp<IChild> &local) {
+sp<IChild> selectService(bool sendRemote, sp<IChild> &local) {
     sp<IChild> toSend;
     if (sendRemote) {
         toSend = IChild::getService("child");
@@ -29,21 +28,20 @@
         toSend = local;
     }
     LOG(INFO) << "SERVER(Fetcher) selectService returning " << toSend.get();
-    _hidl_cb(toSend);
-    return Void();
+    return toSend;
 }
 
 // Methods from ::android::hardware::tests::inheritance::V1_0::IFetcher follow.
-Return<void> Fetcher::getGrandparent(bool sendRemote, getGrandparent_cb _hidl_cb)  {
-    return selectService(sendRemote, _hidl_cb, mPrecious);
+Return<sp<IGrandparent>> Fetcher::getGrandparent(bool sendRemote)  {
+    return selectService(sendRemote, mPrecious);
 }
 
-Return<void> Fetcher::getParent(bool sendRemote, getParent_cb _hidl_cb)  {
-    return selectService(sendRemote, _hidl_cb, mPrecious);
+Return<sp<IParent>> Fetcher::getParent(bool sendRemote)  {
+    return selectService(sendRemote, mPrecious);
 }
 
-Return<void> Fetcher::getChild(bool sendRemote, getChild_cb _hidl_cb)  {
-    return selectService(sendRemote, _hidl_cb, mPrecious);
+Return<sp<IChild>> Fetcher::getChild(bool sendRemote)  {
+    return selectService(sendRemote, mPrecious);
 }
 
 IFetcher* HIDL_FETCH_IFetcher(const char* /* name */) {
diff --git a/tests/inheritance/1.0/default/Fetcher.h b/tests/inheritance/1.0/default/Fetcher.h
index da9b153..979b47f 100644
--- a/tests/inheritance/1.0/default/Fetcher.h
+++ b/tests/inheritance/1.0/default/Fetcher.h
@@ -25,9 +25,9 @@
     Fetcher();
 
     // Methods from ::android::hardware::tests::inheritance::V1_0::IFetcher follow.
-    Return<void> getGrandparent(bool sendRemote, getGrandparent_cb _hidl_cb)  override;
-    Return<void> getParent(bool sendRemote, getParent_cb _hidl_cb)  override;
-    Return<void> getChild(bool sendRemote, getChild_cb _hidl_cb)  override;
+    Return<sp<IGrandparent>> getGrandparent(bool sendRemote)  override;
+    Return<sp<IParent>> getParent(bool sendRemote)  override;
+    Return<sp<IChild>> getChild(bool sendRemote)  override;
 
 private:
     sp<IChild> mPrecious;
diff --git a/tests/msgq/1.0/ITestMsgQ.hal b/tests/msgq/1.0/ITestMsgQ.hal
index 933e39b..e000f55 100644
--- a/tests/msgq/1.0/ITestMsgQ.hal
+++ b/tests/msgq/1.0/ITestMsgQ.hal
@@ -91,4 +91,14 @@
      *
      */
     oneway requestBlockingRead(int32_t count);
+
+    /*
+     * This method requests the service to repeatedly trigger blocking reads.
+     *
+     * @param count Number of messages to read in a single blocking read.
+     * @param numIter Number of blocking reads to trigger.
+     *
+     */
+    oneway requestBlockingReadRepeat(int32_t count, int32_t numIter);
+
 };
diff --git a/tv/cec/1.0/vts/functional/vts/testcases/hal/tv_cec/hidl/host/TvCecHidlTest.py b/tv/cec/1.0/vts/functional/vts/testcases/hal/tv_cec/hidl/host/TvCecHidlTest.py
index cd2374a..dcf21c9 100644
--- a/tv/cec/1.0/vts/functional/vts/testcases/hal/tv_cec/hidl/host/TvCecHidlTest.py
+++ b/tv/cec/1.0/vts/functional/vts/testcases/hal/tv_cec/hidl/host/TvCecHidlTest.py
@@ -37,13 +37,14 @@
         self.dut.shell.one.Execute(
             "setprop vts.hal.vts.hidl.get_stub true")
 
-        self.dut.hal.InitHidlHal(target_type="tv_cec",
-                                 target_basepaths=["/system/lib64"],
-                                 target_version=1.0,
-                                 target_package="android.hardware.tv.cec",
-                                 target_component_name="IHdmiCec",
-                                 hw_binder_service_name="tv.cec",
-                                 bits=64)
+        self.dut.hal.InitHidlHal(
+            target_type="tv_cec",
+            target_basepaths=self.dut.libPaths,
+            target_version=1.0,
+            target_package="android.hardware.tv.cec",
+            target_component_name="IHdmiCec",
+            hw_binder_service_name="tv.cec",
+            bits=64 if self.dut.is64Bit else 32)
 
     def testGetCecVersion1(self):
         """A simple test case which queries the cec version."""
diff --git a/update-makefiles.sh b/update-makefiles.sh
index f153a84..d0cb91c 100755
--- a/update-makefiles.sh
+++ b/update-makefiles.sh
@@ -20,7 +20,9 @@
 for p in $packages; do
   echo "Updating $p";
   hidl-gen -Lmakefile -r android.hardware:hardware/interfaces -r android.hidl:system/libhidl/transport $p;
+  rc=$?; if [[ $rc != 0 ]]; then exit $rc; fi
   hidl-gen -Landroidbp -r android.hardware:hardware/interfaces -r android.hidl:system/libhidl/transport $p;
+  rc=$?; if [[ $rc != 0 ]]; then exit $rc; fi
 done
 
 # subdirectories of hardware/interfaces which contain an Android.bp file
diff --git a/vehicle/2.0/Android.mk b/vehicle/2.0/Android.mk
index 71b587b..9544960 100644
--- a/vehicle/2.0/Android.mk
+++ b/vehicle/2.0/Android.mk
@@ -17,6 +17,177 @@
 
 
 #
+# Build types.hal (CommonIgnitionMonitors)
+#
+GEN := $(intermediates)/android/hardware/vehicle/V2_0/CommonIgnitionMonitors.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+        -Ljava \
+        -randroid.hardware:hardware/interfaces \
+        -randroid.hidl:system/libhidl/transport \
+        android.hardware.vehicle@2.0::types.CommonIgnitionMonitors
+
+$(GEN): $(LOCAL_PATH)/types.hal
+	$(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CompressionIgnitionMonitors)
+#
+GEN := $(intermediates)/android/hardware/vehicle/V2_0/CompressionIgnitionMonitors.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+        -Ljava \
+        -randroid.hardware:hardware/interfaces \
+        -randroid.hidl:system/libhidl/transport \
+        android.hardware.vehicle@2.0::types.CompressionIgnitionMonitors
+
+$(GEN): $(LOCAL_PATH)/types.hal
+	$(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (FuelSystemStatus)
+#
+GEN := $(intermediates)/android/hardware/vehicle/V2_0/FuelSystemStatus.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+        -Ljava \
+        -randroid.hardware:hardware/interfaces \
+        -randroid.hidl:system/libhidl/transport \
+        android.hardware.vehicle@2.0::types.FuelSystemStatus
+
+$(GEN): $(LOCAL_PATH)/types.hal
+	$(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (FuelType)
+#
+GEN := $(intermediates)/android/hardware/vehicle/V2_0/FuelType.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+        -Ljava \
+        -randroid.hardware:hardware/interfaces \
+        -randroid.hidl:system/libhidl/transport \
+        android.hardware.vehicle@2.0::types.FuelType
+
+$(GEN): $(LOCAL_PATH)/types.hal
+	$(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (IgnitionMonitorKind)
+#
+GEN := $(intermediates)/android/hardware/vehicle/V2_0/IgnitionMonitorKind.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+        -Ljava \
+        -randroid.hardware:hardware/interfaces \
+        -randroid.hidl:system/libhidl/transport \
+        android.hardware.vehicle@2.0::types.IgnitionMonitorKind
+
+$(GEN): $(LOCAL_PATH)/types.hal
+	$(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (Obd2FloatSensorIndex)
+#
+GEN := $(intermediates)/android/hardware/vehicle/V2_0/Obd2FloatSensorIndex.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+        -Ljava \
+        -randroid.hardware:hardware/interfaces \
+        -randroid.hidl:system/libhidl/transport \
+        android.hardware.vehicle@2.0::types.Obd2FloatSensorIndex
+
+$(GEN): $(LOCAL_PATH)/types.hal
+	$(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (Obd2IntegerSensorIndex)
+#
+GEN := $(intermediates)/android/hardware/vehicle/V2_0/Obd2IntegerSensorIndex.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+        -Ljava \
+        -randroid.hardware:hardware/interfaces \
+        -randroid.hidl:system/libhidl/transport \
+        android.hardware.vehicle@2.0::types.Obd2IntegerSensorIndex
+
+$(GEN): $(LOCAL_PATH)/types.hal
+	$(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (SecondaryAirStatus)
+#
+GEN := $(intermediates)/android/hardware/vehicle/V2_0/SecondaryAirStatus.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+        -Ljava \
+        -randroid.hardware:hardware/interfaces \
+        -randroid.hidl:system/libhidl/transport \
+        android.hardware.vehicle@2.0::types.SecondaryAirStatus
+
+$(GEN): $(LOCAL_PATH)/types.hal
+	$(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (SparkIgnitionMonitors)
+#
+GEN := $(intermediates)/android/hardware/vehicle/V2_0/SparkIgnitionMonitors.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+        -Ljava \
+        -randroid.hardware:hardware/interfaces \
+        -randroid.hidl:system/libhidl/transport \
+        android.hardware.vehicle@2.0::types.SparkIgnitionMonitors
+
+$(GEN): $(LOCAL_PATH)/types.hal
+	$(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
 # Build types.hal (StatusCode)
 #
 GEN := $(intermediates)/android/hardware/vehicle/V2_0/StatusCode.java
@@ -970,6 +1141,177 @@
 
 
 #
+# Build types.hal (CommonIgnitionMonitors)
+#
+GEN := $(intermediates)/android/hardware/vehicle/V2_0/CommonIgnitionMonitors.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+        -Ljava \
+        -randroid.hardware:hardware/interfaces \
+        -randroid.hidl:system/libhidl/transport \
+        android.hardware.vehicle@2.0::types.CommonIgnitionMonitors
+
+$(GEN): $(LOCAL_PATH)/types.hal
+	$(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CompressionIgnitionMonitors)
+#
+GEN := $(intermediates)/android/hardware/vehicle/V2_0/CompressionIgnitionMonitors.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+        -Ljava \
+        -randroid.hardware:hardware/interfaces \
+        -randroid.hidl:system/libhidl/transport \
+        android.hardware.vehicle@2.0::types.CompressionIgnitionMonitors
+
+$(GEN): $(LOCAL_PATH)/types.hal
+	$(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (FuelSystemStatus)
+#
+GEN := $(intermediates)/android/hardware/vehicle/V2_0/FuelSystemStatus.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+        -Ljava \
+        -randroid.hardware:hardware/interfaces \
+        -randroid.hidl:system/libhidl/transport \
+        android.hardware.vehicle@2.0::types.FuelSystemStatus
+
+$(GEN): $(LOCAL_PATH)/types.hal
+	$(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (FuelType)
+#
+GEN := $(intermediates)/android/hardware/vehicle/V2_0/FuelType.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+        -Ljava \
+        -randroid.hardware:hardware/interfaces \
+        -randroid.hidl:system/libhidl/transport \
+        android.hardware.vehicle@2.0::types.FuelType
+
+$(GEN): $(LOCAL_PATH)/types.hal
+	$(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (IgnitionMonitorKind)
+#
+GEN := $(intermediates)/android/hardware/vehicle/V2_0/IgnitionMonitorKind.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+        -Ljava \
+        -randroid.hardware:hardware/interfaces \
+        -randroid.hidl:system/libhidl/transport \
+        android.hardware.vehicle@2.0::types.IgnitionMonitorKind
+
+$(GEN): $(LOCAL_PATH)/types.hal
+	$(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (Obd2FloatSensorIndex)
+#
+GEN := $(intermediates)/android/hardware/vehicle/V2_0/Obd2FloatSensorIndex.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+        -Ljava \
+        -randroid.hardware:hardware/interfaces \
+        -randroid.hidl:system/libhidl/transport \
+        android.hardware.vehicle@2.0::types.Obd2FloatSensorIndex
+
+$(GEN): $(LOCAL_PATH)/types.hal
+	$(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (Obd2IntegerSensorIndex)
+#
+GEN := $(intermediates)/android/hardware/vehicle/V2_0/Obd2IntegerSensorIndex.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+        -Ljava \
+        -randroid.hardware:hardware/interfaces \
+        -randroid.hidl:system/libhidl/transport \
+        android.hardware.vehicle@2.0::types.Obd2IntegerSensorIndex
+
+$(GEN): $(LOCAL_PATH)/types.hal
+	$(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (SecondaryAirStatus)
+#
+GEN := $(intermediates)/android/hardware/vehicle/V2_0/SecondaryAirStatus.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+        -Ljava \
+        -randroid.hardware:hardware/interfaces \
+        -randroid.hidl:system/libhidl/transport \
+        android.hardware.vehicle@2.0::types.SecondaryAirStatus
+
+$(GEN): $(LOCAL_PATH)/types.hal
+	$(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (SparkIgnitionMonitors)
+#
+GEN := $(intermediates)/android/hardware/vehicle/V2_0/SparkIgnitionMonitors.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+        -Ljava \
+        -randroid.hardware:hardware/interfaces \
+        -randroid.hidl:system/libhidl/transport \
+        android.hardware.vehicle@2.0::types.SparkIgnitionMonitors
+
+$(GEN): $(LOCAL_PATH)/types.hal
+	$(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
 # Build types.hal (StatusCode)
 #
 GEN := $(intermediates)/android/hardware/vehicle/V2_0/StatusCode.java
diff --git a/vehicle/2.0/types.hal b/vehicle/2.0/types.hal
index 28ccb78..62521cb 100644
--- a/vehicle/2.0/types.hal
+++ b/vehicle/2.0/types.hal
@@ -1644,6 +1644,59 @@
         | VehiclePropertyGroup:SYSTEM
         | VehiclePropertyType:COMPLEX
         | VehicleArea:GLOBAL),
+
+    /*
+     * OBD2 Live Sensor Data
+     *
+     * This property uses COMPLEX data to send a snapshot of the current (live)
+     * values of the OBD2 sensors provided by the vehicle.
+     *
+     * Its contents are to be interpreted as follows:
+     * the indices defined in Obd2IntegerSensorIndex are to be used to
+     * read from int32Values;
+     * the indices defined in Obd2FloatSensorIndex are to be used to
+     * read from floatValues.
+     *
+     * For example, int32Values[0] corresponds to FUEL_SYSTEM_STATUS, and
+     * floatValues[0] corresponds to CALCULATED_ENGINE_LOAD.
+     *
+     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+     * @access VehiclePropertyAccess:READ
+     */
+    OBD2_LIVE_FRAME = (
+        0x0D00
+        | VehiclePropertyGroup:SYSTEM
+        | VehiclePropertyType:COMPLEX
+        | VehicleArea:GLOBAL),
+
+    /*
+     * OBD2 Freeze Frame Sensor Data
+     *
+     * This property uses COMPLEX data to send a snapshot of the values of the
+     * OBD2 sensors provided by the vehicle at the time that a diagnostic
+     * troubleshooting code (DTC) was recorded by the vehicle.
+     *
+     * Its contents are to be interpreted as follows:
+     * the indices defined in Obd2IntegerSensorIndex are to be used to
+     * read from int32Values;
+     * the indices defined in Obd2FloatSensorIndex are to be used to
+     * read from floatValues;
+     * stringValue is the DTC that caused this freeze frame to be recorded.
+     *
+     * For example, int32Values[0] corresponds to FUEL_SYSTEM_STATUS, and
+     * floatValues[0] corresponds to CALCULATED_ENGINE_LOAD, and a possible
+     * valid stringValue is "P0176" to indicate a malfunction of the fuel
+     * composition sensor circuit.
+     *
+     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+     * @access VehiclePropertyAccess:READ
+     */
+    OBD2_FREEZE_FRAME = (
+        0x0D01
+        | VehiclePropertyGroup:SYSTEM
+        | VehiclePropertyType:COMPLEX
+        | VehicleArea:GLOBAL),
+
 };
 
 /*
@@ -2531,3 +2584,383 @@
   /* Something unexpected has happened in Vehicle HAL */
   INTERNAL_ERROR = 5,
 };
+
+/* The status of a fuel system as described by the OBD2 specification. */
+enum FuelSystemStatus : int32_t {
+  OPEN_INSUFFICIENT_ENGINE_TEMPERATURE = 1,
+
+  CLOSED_LOOP = 2,
+
+  OPEN_ENGINE_LOAD_OR_DECELERATION = 4,
+
+  OPEN_SYSTEM_FAILURE = 8,
+
+  CLOSED_LOOP_BUT_FEEDBACK_FAULT = 16,
+};
+
+/* Defines which ignition monitors are available to be read. */
+enum IgnitionMonitorKind : int32_t {
+  SPARK = 0,
+
+  COMPRESSION = 1,
+};
+
+/* These ignition monitors are common to both SPARK and COMPRESSION. */
+enum CommonIgnitionMonitors : int32_t {
+  COMPONENTS_AVAILABLE = 0x1 << 0,
+  COMPONENTS_INCOMPLETE = 0x1 << 1,
+
+  FUEL_SYSTEM_AVAILABLE = 0x1 << 2,
+  FUEL_SYSTEM_INCOMPLETE = 0x1 << 3,
+
+  MISFIRE_AVAILABLE = 0x1 << 4,
+  MISFIRE_INCOMPLETE = 0x1 << 5,
+};
+
+/* Ignition monitors available for SPARK vehicles. */
+enum SparkIgnitionMonitors : CommonIgnitionMonitors {
+  EGR_AVAILABLE = 0x1 << 6,
+  EGR_INCOMPLETE = 0x1 << 7,
+
+  OXYGEN_SENSOR_HEATER_AVAILABLE = 0x1 << 8,
+  OXYGEN_SENSOR_HEATER_INCOMPLETE = 0x1 << 9,
+
+  OXYGEN_SENSOR_AVAILABLE = 0x1 << 10,
+  OXYGEN_SENSOR_INCOMPLETE = 0x1 << 11,
+
+  AC_REFRIGERANT_AVAILABLE = 0x1 << 12,
+  AC_REFRIGERANT_INCOMPLETE = 0x1 << 13,
+
+  SECONDARY_AIR_SYSTEM_AVAILABLE = 0x1 << 14,
+  SECONDARY_AIR_SYSTEM_INCOMPLETE = 0x1 << 15,
+
+  EVAPORATIVE_SYSTEM_AVAILABLE = 0x1 << 16,
+  EVAPORATIVE_SYSTEM_INCOMPLETE = 0x1 << 17,
+
+  HEATED_CATALYST_AVAILABLE = 0x1 << 18,
+  HEATED_CATALYST_INCOMPLETE = 0x1 << 19,
+
+  CATALYST_AVAILABLE = 0x1 << 20,
+  CATALYST_INCOMPLETE = 0x1 << 21,
+};
+
+/* Ignition monitors only available for COMPRESSION vehicles. */
+enum CompressionIgnitionMonitors : CommonIgnitionMonitors {
+  EGR_OR_VVT_AVAILABLE = 0x1 << 6,
+  EGR_OR_VVT_INCOMPLETE = 0x1 << 7,
+
+  PM_FILTER_AVAILABLE = 0x1 << 8,
+  PM_FILTER_INCOMPLETE = 0x1 << 9,
+
+  EXHAUST_GAS_SENSOR_AVAILABLE = 0x1 << 10,
+  EXHAUST_GAS_SENSOR_INCOMPLETE = 0x1 << 11,
+
+  BOOST_PRESSURE_AVAILABLE = 0x1 << 12,
+  BOOST_PRESSURE_INCOMPLETE = 0x1 << 13,
+
+  NOx_SCR__AVAILABLE = 0x1 << 14,
+  NOx_SCR_INCOMPLETE = 0x1 << 15,
+
+  NMHC_CATALYST_AVAILABLE = 0x1 << 16,
+  NMHC_CATALYST_INCOMPLETE = 0x1 << 17,
+};
+
+enum SecondaryAirStatus : int32_t {
+  UPSTREAM = 1,
+
+  DOWNSTREAM_OF_CATALYCIC_CONVERTER = 2,
+
+  FROM_OUTSIDE_OR_OFF = 4,
+
+  PUMP_ON_FOR_DIAGNOSTICS = 8,
+};
+
+enum FuelType : int32_t {
+  NOT_AVAILABLE = 0,
+
+  GASOLINE = 1,
+
+  METHANOL = 2,
+
+  ETHANOL = 3,
+
+  DIESEL = 4,
+
+  LPG = 5,
+
+  CNG = 6,
+
+  PROPANE = 7,
+
+  ELECTRIC = 8,
+
+  BIFUEL_RUNNING_GASOLINE = 9,
+
+  BIFUEL_RUNNING_METHANOL = 10,
+
+  BIFUEL_RUNNING_ETHANOL = 11,
+
+  BIFUEL_RUNNING_LPG = 12,
+
+  BIFUEL_RUNNING_CNG = 13,
+
+  BIFUEL_RUNNING_PROPANE = 14,
+
+  BIFUEL_RUNNING_ELECTRIC = 15,
+
+  BIFUEL_RUNNING_ELECTRIC_AND_COMBUSTION = 16,
+
+  HYBRID_GASOLINE = 17,
+
+  HYBRID_ETHANOL = 18,
+
+  HYBRID_DIESEL = 19,
+
+  HYBRID_ELECTRIC = 20,
+
+  HYBRID_RUNNING_ELECTRIC_AND_COMBUSTION = 21,
+
+  HYBRID_REGENERATIVE = 22,
+
+  BIFUEL_RUNNING_DIESEL = 23,
+};
+
+/*
+ * This enum provides the canonical mapping for sensor properties that have an integer value.
+ * The ordering of the values is taken from the OBD2 specification.
+ * Some of the properties are represented as an integer mapping to another enum. In those cases
+ * expect a comment by the property definition describing the enum to look at for the mapping.
+ * Any value greater than the last reserved index is available to vendors to map their extensions.
+ */
+enum Obd2IntegerSensorIndex : int32_t {
+  /* refer to FuelSystemStatus for a description of this value. */
+  FUEL_SYSTEM_STATUS = 0,
+
+  MALFUNCTION_INDICATOR_LIGHT_ON = 1,
+
+  /* refer to IgnitionMonitorKind for a description of this value. */
+  IGNITION_MONITORS_SUPPORTED = 2,
+
+  /*
+   * The value of this sensor is a bitmask that specifies whether ignition-specific
+   * tests are available and whether they are complete. The semantics of the individual
+   * bits in this value are given by, respectively, SparkIgnitionMonitors and
+   * CompressionIgnitionMonitors depending on the value of IGNITION_MONITORS_SUPPORTED.
+  /*
+  IGNITION_SPECIFIC_MONITORS = 3,
+
+  INTAKE_AIR_TEMPERATURE = 4,
+
+  /* refer to SecondaryAirStatus for a description of this value. */
+  COMMANDED_SECONDARY_AIR_STATUS = 5,
+
+  NUM_OXYGEN_SENSORS_PRESENT = 6,
+
+  RUNTIME_SINCE_ENGINE_START = 7,
+
+  DISTANCE_TRAVELED_WITH_MALFUNCTION_INDICATOR_LIGHT_ON = 8,
+
+  WARMUPS_SINCE_CODES_CLEARED = 9,
+
+  DISTANCE_TRAVELED_SINCE_CODES_CLEARED = 10,
+
+  ABSOLUTE_BAROMETRIC_PRESSURE = 11,
+
+  CONTROL_MODULE_VOLTAGE = 12,
+
+  AMBIENT_AIR_TEMPERATURE = 13,
+
+  TIME_WITH_MALFUNCTION_LIGHT_ON = 14,
+
+  TIME_SINCE_TROUBLE_CODES_CLEARED = 15,
+
+  MAX_FUEL_AIR_EQUIVALENCE_RATIO = 16,
+
+  MAX_OXYGEN_SENSOR_VOLTAGE = 17,
+
+  MAX_OXYGEN_SENSOR_CURRENT = 18,
+
+  MAX_INTAKE_MANIFOLD_ABSOLUTE_PRESSURE = 19,
+
+  MAX_AIR_FLOW_RATE_FROM_MASS_AIR_FLOW_SENSOR = 20,
+
+  /* refer to FuelType for a description of this value. */
+  FUEL_TYPE = 21,
+
+  FUEL_RAIL_ABSOLUTE_PRESSURE = 22,
+
+  ENGINE_OIL_TEMPERATURE = 23,
+
+  DRIVER_DEMAND_PERCENT_TORQUE = 24,
+
+  ENGINE_ACTUAL_PERCENT_TORQUE = 25,
+
+  ENGINE_REFERENCE_PERCENT_TORQUE = 26,
+
+  ENGINE_PERCENT_TORQUE_DATA_IDLE = 27,
+
+  ENGINE_PERCENT_TORQUE_DATA_POINT1 = 28,
+
+  ENGINE_PERCENT_TORQUE_DATA_POINT2 = 29,
+
+  ENGINE_PERCENT_TORQUE_DATA_POINT3 = 30,
+
+  ENGINE_PERCENT_TORQUE_DATA_POINT4 = 31,
+
+  LAST_SYSTEM_INDEX = ENGINE_PERCENT_TORQUE_DATA_POINT4,
+
+  VENDOR_START_INDEX = LAST_SYSTEM_INDEX + 1,
+};
+
+/*
+ * This enum provides the canonical mapping for sensor properties that have a floating-point value.
+ * The ordering of the values is taken from the OBD2 specification.
+ * Any value greater than the last reserved index is available to vendors to map their extensions.
+ */
+enum Obd2FloatSensorIndex : int32_t {
+  CALCULATED_ENGINE_LOAD = 0,
+
+  ENGINE_COOLANT_TEMPERATURE = 1,
+
+  SHORT_TERM_FUEL_TRIM_BANK1 = 2,
+
+  LONG_TERM_FUEL_TRIM_BANK1 = 3,
+
+  SHORT_TERM_FUEL_TRIM_BANK2 = 4,
+
+  LONG_TERM_FUEL_TRIM_BANK2 = 5,
+
+  FUEL_PRESSURE = 6,
+
+  INTAKE_MANIFOLD_ABSOLUTE_PRESSURE = 7,
+
+  ENGINE_RPM = 8,
+
+  VEHICLE_SPEED = 9,
+
+  TIMING_ADVANCE = 10,
+
+  MAF_AIR_FLOW_RATE = 11,
+
+  THROTTLE_POSITION = 12,
+
+  OXYGEN_SENSOR1_VOLTAGE = 13,
+
+  OXYGEN_SENSOR1_SHORT_TERM_FUEL_TRIM = 14,
+
+  OXYGEN_SENSOR1_FUEL_AIR_EQUIVALENCE_RATIO = 15,
+
+  OXYGEN_SENSOR2_VOLTAGE = 16,
+
+  OXYGEN_SENSOR2_SHORT_TERM_FUEL_TRIM = 17,
+
+  OXYGEN_SENSOR2_FUEL_AIR_EQUIVALENCE_RATIO = 18,
+
+  OXYGEN_SENSOR3_VOLTAGE = 19,
+
+  OXYGEN_SENSOR3_SHORT_TERM_FUEL_TRIM = 20,
+
+  OXYGEN_SENSOR3_FUEL_AIR_EQUIVALENCE_RATIO = 21,
+
+  OXYGEN_SENSOR4_VOLTAGE = 22,
+
+  OXYGEN_SENSOR4_SHORT_TERM_FUEL_TRIM = 23,
+
+  OXYGEN_SENSOR4_FUEL_AIR_EQUIVALENCE_RATIO = 24,
+
+  OXYGEN_SENSOR5_VOLTAGE = 25,
+
+  OXYGEN_SENSOR5_SHORT_TERM_FUEL_TRIM = 26,
+
+  OXYGEN_SENSOR5_FUEL_AIR_EQUIVALENCE_RATIO = 27,
+
+  OXYGEN_SENSOR6_VOLTAGE = 28,
+
+  OXYGEN_SENSOR6_SHORT_TERM_FUEL_TRIM = 29,
+
+  OXYGEN_SENSOR6_FUEL_AIR_EQUIVALENCE_RATIO = 30,
+
+  OXYGEN_SENSOR7_VOLTAGE = 31,
+
+  OXYGEN_SENSOR7_SHORT_TERM_FUEL_TRIM = 32,
+
+  OXYGEN_SENSOR7_FUEL_AIR_EQUIVALENCE_RATIO = 33,
+
+  OXYGEN_SENSOR8_VOLTAGE = 34,
+
+  OXYGEN_SENSOR8_SHORT_TERM_FUEL_TRIM = 35,
+
+  OXYGEN_SENSOR8_FUEL_AIR_EQUIVALENCE_RATIO = 36,
+
+  FUEL_RAIL_PRESSURE = 37,
+
+  FUEL_RAIL_GAUGE_PRESSURE = 38,
+
+  COMMANDED_EXHAUST_GAS_RECIRCULATION = 39,
+
+  EXHAUST_GAS_RECIRCULATION_ERROR = 40,
+
+  COMMANDED_EVAPORATIVE_PURGE = 41,
+
+  FUEL_TANK_LEVEL_INPUT = 42,
+
+  EVAPORATION_SYSTEM_VAPOR_PRESSURE = 43,
+
+  CATALYST_TEMPERATURE_BANK1_SENSOR1 = 44,
+
+  CATALYST_TEMPERATURE_BANK2_SENSOR1 = 45,
+
+  CATALYST_TEMPERATURE_BANK1_SENSOR2 = 46,
+
+  CATALYST_TEMPERATURE_BANK2_SENSOR2 = 47,
+
+  ABSOLUTE_LOAD_VALUE = 48,
+
+  FUEL_AIR_COMMANDED_EQUIVALENCE_RATIO = 49,
+
+  RELATIVE_THROTTLE_POSITION = 50,
+
+  ABSOLUTE_THROTTLE_POSITION_B = 51,
+
+  ABSOLUTE_THROTTLE_POSITION_C = 52,
+
+  ACCELERATOR_PEDAL_POSITION_D = 53,
+
+  ACCELERATOR_PEDAL_POSITION_E = 54,
+
+  ACCELERATOR_PEDAL_POSITION_F = 55,
+
+  COMMANDED_THROTTLE_ACTUATOR = 56,
+
+  ETHANOL_FUEL_PERCENTAGE = 57,
+
+  ABSOLUTE_EVAPORATION_SYSTEM_VAPOR_PRESSURE = 58,
+
+  SHORT_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK1 = 59,
+
+  SHORT_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK2 = 60,
+
+  SHORT_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK3 = 61,
+
+  SHORT_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK4 = 62,
+
+  LONG_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK1 = 63,
+
+  LONG_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK2 = 64,
+
+  LONG_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK3 = 65,
+
+  LONG_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK4 = 66,
+
+  RELATIVE_ACCELERATOR_PEDAL_POSITION = 67,
+
+  HYBRID_BATTERY_PACK_REMAINING_LIFE = 68,
+
+  FUEL_INJECTION_TIMING = 69,
+
+  ENGINE_FUEL_RATE = 70,
+
+  LAST_SYSTEM_INDEX = ENGINE_FUEL_RATE,
+
+  VENDOR_START_INDEX = LAST_SYSTEM_INDEX + 1,
+};
diff --git a/vehicle/2.0/vts/functional/vts/testcases/hal/vehicle/hidl/host/VehicleHidlTest.py b/vehicle/2.0/vts/functional/vts/testcases/hal/vehicle/hidl/host/VehicleHidlTest.py
index 8da36d1..e17c72d 100644
--- a/vehicle/2.0/vts/functional/vts/testcases/hal/vehicle/hidl/host/VehicleHidlTest.py
+++ b/vehicle/2.0/vts/functional/vts/testcases/hal/vehicle/hidl/host/VehicleHidlTest.py
@@ -40,11 +40,12 @@
 
         self.dut.hal.InitHidlHal(
             target_type="vehicle",
-            target_basepaths=["/system/lib64"],
+            target_basepaths=self.dut.libPaths,
             target_version=2.0,
             target_package="android.hardware.vehicle",
             target_component_name="IVehicle",
-            bits=64)
+            hw_binder_service_name="Vehicle",
+            bits=64 if self.dut.is64Bit else 32)
 
     def tearDownClass(self):
         """ If profiling is enabled for the test, collect the profiling data
diff --git a/vibrator/1.0/vts/functional/vts/testcases/hal/vibrator/hidl/host/VibratorHidlTest.py b/vibrator/1.0/vts/functional/vts/testcases/hal/vibrator/hidl/host/VibratorHidlTest.py
index b36f47a..da70474 100644
--- a/vibrator/1.0/vts/functional/vts/testcases/hal/vibrator/hidl/host/VibratorHidlTest.py
+++ b/vibrator/1.0/vts/functional/vts/testcases/hal/vibrator/hidl/host/VibratorHidlTest.py
@@ -44,12 +44,12 @@
 
         self.dut.hal.InitHidlHal(
             target_type="vibrator",
-            target_basepaths=["/system/lib64"],
+            target_basepaths=self.dut.libPaths,
             target_version=1.0,
             target_package="android.hardware.vibrator",
             target_component_name="IVibrator",
             hw_binder_service_name="vibrator",
-            bits=64)
+            bits=64 if self.dut.is64Bit else 32)
 
     def tearDownClass(self):
         """ If profiling is enabled for the test, collect the profiling data
diff --git a/vr/1.0/vts/functional/Android.bp b/vr/1.0/vts/functional/Android.bp
index 2929fe7..551f27c 100644
--- a/vr/1.0/vts/functional/Android.bp
+++ b/vr/1.0/vts/functional/Android.bp
@@ -26,7 +26,11 @@
     ],
     static_libs: ["libgtest"],
     cflags: [
-        "-O0",
+       "--coverage",
+       "-O0",
         "-g",
     ],
+    ldflags: [
+        "--coverage"
+    ]
 }
diff --git a/vr/1.0/vts/functional/vts/testcases/hal/vr/hidl/host/Android.mk b/vr/1.0/vts/functional/vts/testcases/hal/vr/hidl/host/Android.mk
new file mode 100644
index 0000000..9388b8d
--- /dev/null
+++ b/vr/1.0/vts/functional/vts/testcases/hal/vr/hidl/host/Android.mk
@@ -0,0 +1,23 @@
+#
+# Copyright (C) 2016 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := VrHidlTest
+VTS_CONFIG_SRC_DIR := testcases/hal/vr/hidl/host
+include test/vts/tools/build/Android.host_config.mk
diff --git a/vr/1.0/vts/functional/vts/testcases/hal/vr/hidl/host/AndroidTest.xml b/vr/1.0/vts/functional/vts/testcases/hal/vr/hidl/host/AndroidTest.xml
new file mode 100644
index 0000000..1cd2a80
--- /dev/null
+++ b/vr/1.0/vts/functional/vts/testcases/hal/vr/hidl/host/AndroidTest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+<configuration description="Config for VTS HAL VR test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
+        <option name="push-group" value="HidlHalTest.push" />
+        <option name="cleanup" value="true" />
+        <option name="push" value="spec/hardware/interfaces/vr/1.0/vts/Vr.vts->/data/local/tmp/spec/Vr.vts" />
+    </target_preparer>
+    <target_preparer class="com.android.tradefed.targetprep.VtsPythonVirtualenvPreparer" />
+    <test class="com.android.tradefed.testtype.VtsMultiDeviceTest">
+        <option name="test-module-name" value="VrHidlTest" />
+        <option name="test-case-path" value="vts/testcases/hal/vr/hidl/host/VrHidlTest" />
+    </test>
+</configuration>
diff --git a/vr/1.0/vts/functional/vts/testcases/hal/vr/hidl/host/VrHidlTest.py b/vr/1.0/vts/functional/vts/testcases/hal/vr/hidl/host/VrHidlTest.py
new file mode 100644
index 0000000..9ed378f
--- /dev/null
+++ b/vr/1.0/vts/functional/vts/testcases/hal/vr/hidl/host/VrHidlTest.py
@@ -0,0 +1,80 @@
+#!/usr/bin/env python3.4
+#
+# Copyright (C) 2016 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.
+#
+
+import logging
+import time
+
+from vts.runners.host import asserts
+from vts.runners.host import base_test_with_webdb
+from vts.runners.host import test_runner
+from vts.utils.python.controllers import android_device
+from vts.utils.python.profiling import profiling_utils
+
+
+class VrHidlTest(base_test_with_webdb.BaseTestWithWebDbClass):
+    """A simple testcase for the VR HIDL HAL."""
+
+    def setUpClass(self):
+        """Creates a mirror and turns on the framework-layer VR service."""
+        self.dut = self.registerController(android_device)[0]
+
+        self.dut.shell.InvokeTerminal("one")
+        self.dut.shell.one.Execute("setenforce 0")  # SELinux permissive mode
+
+        # Test using the binderized mode
+        self.dut.shell.one.Execute(
+            "setprop vts.hal.vts.hidl.get_stub true")
+
+        if self.enable_profiling:
+            profiling_utils.EnableVTSProfiling(self.dut.shell.one)
+
+        self.dut.hal.InitHidlHal(
+            target_type="vr",
+            target_basepaths=["/system/lib64"],
+            target_version=1.0,
+            target_package="android.hardware.vr",
+            target_component_name="IVr",
+            bits=64)
+
+    def tearDownClass(self):
+        """ If profiling is enabled for the test, collect the profiling data
+            and disable profiling after the test is done.
+        """
+        if self.enable_profiling:
+            profiling_trace_path = getattr(
+                self, self.VTS_PROFILING_TRACING_PATH, "")
+            self.ProcessAndUploadTraceData(self.dut, profiling_trace_path)
+            profiling_utils.DisableVTSProfiling(self.dut.shell.one)
+
+    def testVrBasic(self):
+        """A simple test case which just calls each registered function."""
+        result = self.dut.hal.vr.init()
+        logging.info("init result: %s", result)
+
+        time.sleep(1)
+
+        result = self.dut.hal.vr.setVrMode(True)
+        logging.info("setVrMode(true) result: %s", result)
+
+        time.sleep(1)
+
+        result = self.dut.hal.vr.setVrMode(False)
+        logging.info("setVrMode(false) result: %s", result)
+
+
+if __name__ == "__main__":
+    test_runner.main()
diff --git a/vr/1.0/vts/functional/vts/testcases/hal/vr/hidl/host/__init__.py b/vr/1.0/vts/functional/vts/testcases/hal/vr/hidl/host/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/vr/1.0/vts/functional/vts/testcases/hal/vr/hidl/host/__init__.py
diff --git a/vr/1.0/vts/functional/vts/testcases/hal/vr/hidl/target/AndroidTest.xml b/vr/1.0/vts/functional/vts/testcases/hal/vr/hidl/target/AndroidTest.xml
index a29c23b..888a585 100644
--- a/vr/1.0/vts/functional/vts/testcases/hal/vr/hidl/target/AndroidTest.xml
+++ b/vr/1.0/vts/functional/vts/testcases/hal/vr/hidl/target/AndroidTest.xml
@@ -26,6 +26,7 @@
             "/>
         <option name="binary-test-type" value="gtest" />
         <option name="test-timeout" value="1m" />
-    </test>
+        <option name="test-config-path" value="vts/testcases/hal/vr/hidl/target/VrHidlTargetTest.config" />
+</test>
 </configuration>
 
diff --git a/vr/1.0/vts/functional/vts/testcases/hal/vr/hidl/target/VrHidlTargetTest.config b/vr/1.0/vts/functional/vts/testcases/hal/vr/hidl/target/VrHidlTargetTest.config
new file mode 100644
index 0000000..ec01b5f
--- /dev/null
+++ b/vr/1.0/vts/functional/vts/testcases/hal/vr/hidl/target/VrHidlTargetTest.config
@@ -0,0 +1,25 @@
+{
+    "use_gae_db": true,
+    "coverage": true,
+    "modules": [{
+                    "module_name": "system/lib64/hw/vr.marlin",
+                    "git_project": {
+                        "name": "device/google/marlin",
+                        "path": "device/google/marlin"
+                    }
+                },
+                {
+                    "module_name": "system/lib64/hw/vr.sailfish",
+                    "git_project": {
+                        "name": "device/google/marlin",
+                        "path": "device/google/marlin"
+                    }
+                },
+                {
+                    "module_name": "system/lib64/hw/android.hardware.vr@1.0-impl",
+                    "git_project": {
+                        "name": "platform/hardware/interfaces",
+                        "path": "hardware/interfaces"
+                    }
+                }]
+}
diff --git a/wifi/1.0/default/wifi.cpp b/wifi/1.0/default/wifi.cpp
index 332363d..c06abe8 100644
--- a/wifi/1.0/default/wifi.cpp
+++ b/wifi/1.0/default/wifi.cpp
@@ -103,18 +103,18 @@
     chip_ = new WifiChip(kChipId, legacy_hal_, mode_controller_);
     run_state_ = RunState::STARTED;
     for (const auto& callback : event_callbacks_) {
-      if (!callback->onStart().getStatus().isOk()) {
+      if (!callback->onStart().isOk()) {
         LOG(ERROR) << "Failed to invoke onStart callback";
       };
     }
     for (const auto& callback : event_callbacks_) {
-      if (!callback->onFailure(wifi_status).getStatus().isOk()) {
+      if (!callback->onFailure(wifi_status).isOk()) {
         LOG(ERROR) << "Failed to invoke onFailure callback";
       }
     }
   } else {
     for (const auto& callback : event_callbacks_) {
-      if (!callback->onFailure(wifi_status).getStatus().isOk()) {
+      if (!callback->onFailure(wifi_status).isOk()) {
         LOG(ERROR) << "Failed to invoke onFailure callback";
       }
     }
@@ -132,13 +132,13 @@
   WifiStatus wifi_status = stopLegacyHalAndDeinitializeModeController();
   if (wifi_status.code == WifiStatusCode::SUCCESS) {
     for (const auto& callback : event_callbacks_) {
-      if (!callback->onStop().getStatus().isOk()) {
+      if (!callback->onStop().isOk()) {
         LOG(ERROR) << "Failed to invoke onStop callback";
       };
     }
   } else {
     for (const auto& callback : event_callbacks_) {
-      if (!callback->onFailure(wifi_status).getStatus().isOk()) {
+      if (!callback->onFailure(wifi_status).isOk()) {
         LOG(ERROR) << "Failed to invoke onFailure callback";
       }
     }
diff --git a/wifi/1.0/default/wifi_nan_iface.cpp b/wifi/1.0/default/wifi_nan_iface.cpp
index a897520..8d5cbc9 100644
--- a/wifi/1.0/default/wifi_nan_iface.cpp
+++ b/wifi/1.0/default/wifi_nan_iface.cpp
@@ -59,7 +59,7 @@
     hidl_msg.header = hidl_header;
     hidl_msg.body = hidl_body;
     for (const auto& callback : event_callbacks_) {
-      if (!callback->notifyPublishResponse(id, hidl_msg).getStatus().isOk()) {
+      if (!callback->notifyPublishResponse(id, hidl_msg).isOk()) {
         LOG(ERROR) << "Failed to invoke the callback";
       }
     }