Camera: default implementation of device 3.2

Test: compile
Bug: 30985004
Change-Id: Ibb48673840de6a5f7c75dc6993d5457a272177a2
diff --git a/camera/Android.bp b/camera/Android.bp
index a373bf4..fb6de9e 100644
--- a/camera/Android.bp
+++ b/camera/Android.bp
@@ -1,8 +1,10 @@
 // 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",
 ]
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..d8a424e
--- /dev/null
+++ b/camera/common/1.0/default/CameraModule.cpp
@@ -0,0 +1,437 @@
+/*
+ * 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() {
+    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() {
+    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();
+    }
+}
+
+int CameraModule::setTorchMode(const char* camera_id, bool enable) {
+    int res;
+    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() {
+    return mModule->common.module_api_version;
+}
+
+const char* CameraModule::getModuleName() {
+    return mModule->common.name;
+}
+
+uint16_t CameraModule::getHalApiVersion() {
+    return mModule->common.hal_api_version;
+}
+
+const char* CameraModule::getModuleAuthor() {
+    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..907c807
--- /dev/null
+++ b/camera/common/1.0/default/include/CameraModule.h
@@ -0,0 +1,85 @@
+/*
+ * 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();
+    int openLegacy(const char* id, uint32_t halVersion, struct hw_device_t** device);
+    int setCallbacks(const camera_module_callbacks_t *callbacks);
+    bool isVendorTagDefined();
+    void getVendorTagOps(vendor_tag_ops_t* ops);
+    int setTorchMode(const char* camera_id, bool enable);
+    uint16_t getModuleApiVersion();
+    const char* getModuleName();
+    uint16_t getHalApiVersion();
+    const char* getModuleAuthor();
+    // 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/1.0/ICameraDevice.hal b/camera/device/1.0/ICameraDevice.hal
index d232a67..acca9a7 100644
--- a/camera/device/1.0/ICameraDevice.hal
+++ b/camera/device/1.0/ICameraDevice.hal
@@ -78,6 +78,11 @@
      */
     getCameraInfo() generates (Status status, CameraInfo info);
 
+    // TODO: add query setTorch mode support so camera service can tell whether
+    //       it needs to simulate torch or not (without calling setTorchMode
+    //       which is visible to end user)
+    //       Should this be put to device hal or provider hal?
+
     /**
      * setTorchMode:
      *
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..51a29ec
--- /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(Status::INTERNAL_ERROR, 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..7e43cd7
--- /dev/null
+++ b/camera/device/3.2/default/CameraDeviceSession.cpp
@@ -0,0 +1,646 @@
+/*
+ * 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) {
+            fd = dup(handle->data[0]);
+            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)
+    {
+        if (fd >= 0) {
+            close(fd);
+        }
+    }
+
+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>& allBufs,
+        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
+    allBufs.resize(numBufs);
+    allFences.resize(numBufs);
+    for (size_t i = 0; i < numOutputBufs; i++) {
+        allBufs[i] = request.outputBuffers[i].buffer.getNativeHandle();
+    }
+    if (hasInputBuf) {
+        allBufs[numOutputBufs] = request.inputBuffer.buffer.getNativeHandle();
+    }
+    for (size_t i = 0; i < numBufs; i++) {
+        buffer_handle_t buf = allBufs[i];
+        sHandleImporter.importBuffer(buf);
+        if (buf == nullptr) {
+            ALOGE("%s: output buffer %zu is invalid!", __FUNCTION__, i);
+            cleanupInflightBufferFences(allBufs, i, allFences, 0);
+            return Status::INTERNAL_ERROR;
+        } else {
+            allBufs[i] = 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);
+            cleanupInflightBufferFences(allBufs, numBufs, 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__);
+            cleanupInflightBufferFences(allBufs, numBufs, allFences, numOutputBufs);
+            return Status::INTERNAL_ERROR;
+        }
+    }
+    return Status::OK;
+}
+
+void CameraDeviceSession::cleanupInflightBufferFences(
+        hidl_vec<buffer_handle_t>& allBufs, size_t numBufs,
+        hidl_vec<int>& allFences, size_t numFences) {
+    for (size_t j = 0; j < numBufs; j++) {
+        sHandleImporter.freeBuffer(allBufs[j]);
+    }
+    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();
+    if (!mInflightBuffers.empty()) {
+        ALOGE("%s: trying to configureStreams while there are still %zu inflight buffers!",
+                __FUNCTION__, mInflightBuffers.size());
+        status = Status::INTERNAL_ERROR;
+    }
+
+    HalStreamConfiguration outStreams;
+    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();
+
+        mStreamMap.clear();
+        for (uint32_t i = 0; i < stream_list.num_streams; i++) {
+            Camera3Stream stream;
+            convertFromHidl(requestedConfiguration.streams[i], &stream);
+            mStreamMap[stream.mId] = stream;
+            streams[i] = &mStreamMap[stream.mId];
+        }
+
+        ATRACE_BEGIN("camera3->configure_streams");
+        status_t ret = mDevice->ops->configure_streams(mDevice, &stream_list);
+        ATRACE_END();
+
+        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> allBufs;
+    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, allBufs, allFences);
+    if (status != Status::OK) {
+        return status;
+    }
+
+    if (hasInputBuf) {
+        auto key = std::make_pair(request.inputBuffer.streamId, request.frameNumber);
+        auto& bufCache = mInflightBuffers[key] = StreamBufferCache{};
+        // The last parameter (&bufCache) must be in heap, or we will
+        // send a pointer pointing to stack memory to HAL and later HAL will break
+        // when trying to accessing it after this call returned.
+        convertFromHidl(
+                allBufs[numOutputBufs], request.inputBuffer.status,
+                &mStreamMap[request.inputBuffer.streamId], allFences[numOutputBufs],
+                &bufCache);
+        halRequest.input_buffer = &(bufCache.mStreamBuffer);
+    } else {
+        halRequest.input_buffer = nullptr;
+    }
+
+    halRequest.num_output_buffers = numOutputBufs;
+    hidl_vec<camera3_stream_buffer_t> outHalBufs;
+    outHalBufs.resize(numOutputBufs);
+    for (size_t i = 0; i < numOutputBufs; i++) {
+        auto key = std::make_pair(request.outputBuffers[i].streamId, request.frameNumber);
+        auto& bufCache = mInflightBuffers[key] = StreamBufferCache{};
+        // The last parameter (&bufCache) must be in heap, or we will
+        // send a pointer pointing to stack memory to HAL and later HAL will break
+        // when trying to accessing it after this call returned.
+        convertFromHidl(
+                allBufs[i], request.outputBuffers[i].status,
+                &mStreamMap[request.outputBuffers[i].streamId], allFences[i],
+                &bufCache);
+        outHalBufs[i] = bufCache.mStreamBuffer;
+    }
+    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) {
+        ALOGE("%s: HAL process_capture_request call failed!", __FUNCTION__);
+
+        cleanupInflightBufferFences(allBufs, numBufs, 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) {
+        ATRACE_BEGIN("camera3->close");
+        mDevice->common.close(&mDevice->common);
+        ATRACE_END();
+        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;
+    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 {
+        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];
+        }
+    }
+
+    d->mCallback->processCaptureResult(result);
+
+    // Free cached buffer/fences.
+    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].mStreamBuffer.acquire_fence);
+        sHandleImporter.freeBuffer(d->mInflightBuffers[key].mBuffer);
+        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].mStreamBuffer.acquire_fence);
+        sHandleImporter.freeBuffer(d->mInflightBuffers[key].mBuffer);
+        d->mInflightBuffers.erase(key);
+    }
+
+    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) {
+        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..3e01b1a
--- /dev/null
+++ b/camera/device/3.2/default/CameraDeviceSession.h
@@ -0,0 +1,129 @@
+/*
+ * 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 "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;
+    // (streamID, frameNumber) -> inflight buffer cache
+    std::map<std::pair<int, uint32_t>, StreamBufferCache>  mInflightBuffers;
+
+    bool mInitFail;
+    bool initialize();
+
+    Status initStatus() const;
+
+    // Validate and import request's input buffer and acquire fence
+    static Status importRequest(
+            const CaptureRequest& request,
+            hidl_vec<buffer_handle_t>& allBufs,
+            hidl_vec<int>& allFences);
+
+    static void cleanupInflightBufferFences(
+            hidl_vec<buffer_handle_t>& allBufs, size_t numBufs,
+            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..ae83e7d
--- /dev/null
+++ b/camera/device/3.2/default/convert.cpp
@@ -0,0 +1,138 @@
+/*
+ * 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) {
+    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 bufIn, BufferStatus status, camera3_stream_t* stream, int acquireFence,
+        StreamBufferCache* dst) {
+    dst->mBuffer = bufIn;
+    dst->mStreamBuffer.stream = stream;
+    dst->mStreamBuffer.buffer = &dst->mBuffer;
+    dst->mStreamBuffer.status = (int) status;
+    dst->mStreamBuffer.acquire_fence = acquireFence;
+    dst->mStreamBuffer.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:
+            dst->msg.error.frameNumber = src->message.error.frame_number;
+            // 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
+            dst->msg.error.errorStreamId =
+                    static_cast<Camera3Stream*>(src->message.error.error_stream)->mId;
+            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..f5ea564
--- /dev/null
+++ b/camera/device/3.2/default/include/convert.h
@@ -0,0 +1,81 @@
+/*
+ * 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 {
+
+// Cacheing the buffer/fence from camera service so HAL can reference the pointer after the
+// processCaptureRequest call has returned.
+// Remove the cache when:
+//     1. HAL API call failed, or
+//     2. HAL returns the buffer and the callback to camera service has returned
+struct StreamBufferCache {
+    buffer_handle_t mBuffer;
+    camera3_stream_buffer_t mStreamBuffer;
+};
+
+// 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);
+
+// dst->mStreamBuffer.buffer will be pointing to dst->mBuffer.
+// Most likely dst will be passed to HAL and HAL will try to access mStreamBuffer.buffer
+// after the API call returns. In that case caller must not use a local variable
+// within the scope of the API call to hold dst, because then dst->mStreamBuffer.buffer will be
+// invalid after the API call returns.
+void convertFromHidl(
+        buffer_handle_t, BufferStatus, camera3_stream_t*, int acquireFence, // inputs
+        StreamBufferCache* 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 a7ab4ab..1e0924c 100644
--- a/camera/device/3.2/types.hal
+++ b/camera/device/3.2/types.hal
@@ -403,7 +403,9 @@
  */
 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;
 
@@ -605,7 +607,7 @@
 };
 
 /**
- * MotifyMsg:
+ * NotifyMsg:
  *
  * The message structure sent to ICameraDevice3Callback::notify()
  */